Vue入门到实战(day4):Vue 表单绑定、自定义指令与Vue生命周期(附代码案例)

        在 Vue 开发中,表单数据收集、指令使用和生命周期管理是核心基础。掌握这些知识点能让你更高效地构建交互式页面,本文将结合实例详细拆解,帮助你快速上手实战。

一、表单数据收集:v-model 的全面应用

v-model 是 Vue 实现表单双向绑定的核心指令,其收集数据的规则随表单元素类型变化,配合修饰符可满足多样化需求。

1. 输入框类表单(text/password/number)

  • 核心逻辑:v-model 直接收集元素的 value 值,用户输入内容即 value 值。
  • 常用修饰符:
    • trim:自动过滤输入内容首尾的空格,适用于账号、昵称等场景。
    • number:将输入的字符串转为有效数字,适用于年龄、金额等数值类输入。
    • lazy:失去焦点后再收集数据,减少实时数据更新的性能消耗。
<div id="root">
  <form @submit.prevent="submitForm">
    账号:<input type="text" v-model.trim="userInfo.a***ount"><br/><br/>
    密码:<input type="password" v-model="userInfo.password"><br/><br/>
    年龄:<input type="number" v-model.number="userInfo.age"><br/><br/>
    <button>提交</button>
  </form>
</div>
<script>
Vue.config.productionTip = false
new Vue({
  el:'#root',
  data:{
    userInfo:{ a***ount:'', password:'', age:18 }
  },
  methods: {
    submitForm(){ console.log(JSON.stringify(this.userInfo)) }
  }
})
</script>

2. 单选按钮(radio)

  • 核心要求:必须为每个单选框配置 value 属性,v-model 收集的是选中项的 value 值。
  • 注意事项:无需手动设置 name 属性,v-model 会自动实现互斥效果。

<div id="root">
  <form @submit.prevent="submitForm">
    性别:
    男<input type="radio" v-model="userInfo.sex" value="male">
    女<input type="radio" v-model="userInfo.sex" value="female">
  </form>
</div>
<script>
Vue.config.productionTip = false
new Vue({
  el:'#root',
  data:{ userInfo:{ sex:'female' } }, // 默认选中女性
  methods: { submitForm(){ console.log(this.userInfo) } }
})
</script>

3. 复选框(checkbox)

  • 无 value 属性:收集的是布尔值(true = 勾选,false = 未勾选),适用于同意协议等单个勾选场景。
  • 有 value 属性:
    • 初始值为非数组:收集布尔值(是否勾选)。
    • 初始值为数组:收集所有勾选项的 value 值组成的数组,适用于多选项(如爱好选择)。

4. 下拉选择框(select)与文本域(textarea)

  • 下拉框:v-model 绑定选中项的 value 值,option 标签需配置 value 属性。
  • 文本域:与输入框用法一致,支持 lazy 等修饰符,无需手动设置 rows 属性(Vue 自动适配)。
<div id="root">
  <form @submit.prevent="submitForm">
    爱好:
    学习<input type="checkbox" v-model="userInfo.hobby" value="study">
    打游戏<input type="checkbox" v-model="userInfo.hobby" value="game">
    <br/><br/>
    所属校区:
    <select v-model="userInfo.city">
      <option value="">请选择校区</option>
      <option value="beijing">北京</option>
      <option value="shanghai">上海</option>
    </select>
    <br/><br/>
    其他信息:<textarea v-model.lazy="userInfo.other"></textarea>
    <button>提交</button>
  </form>
</div>
<script>
Vue.config.productionTip = false
new Vue({
  el:'#root',
  data:{
    userInfo:{ hobby:[], city:'beijing', other:'' }
  },
  methods: { submitForm(){ console.log(this.userInfo) } }
})
</script>

二、Vue 指令:内置指令与自定义指令

指令是 Vue 操作 DOM 的核心方式,分为内置指令和自定义指令,用于实现页面渲染、DOM 操作等功能。

1. 常用内置指令

  • v-text:渲染文本内容,会替换节点原有内容(替代插值语法 {{}},使用较少)。
  • v-html:渲染包含 HTML 结构的内容,需注意 XSS 安全风险(仅用于可信内容,禁止用于用户输入)。
  • v-cloak:解决网速较慢时页面显示 {{xxx}} 的问题,配合 CSS 使用([v-cloak]{display:none})。
  • v-once:仅渲染一次,后续数据更新不会重新渲染(适用于静态内容,优化性能)。
  • v-pre:跳过节点编译过程,加快 Vue 编译速度(适用于无指令、无插值的纯静态节点)。

2. 自定义指令

当内置指令无法满足需求时,可自定义指令实现特定功能,支持全局注册和局部注册。

核心语法
  • 全局注册:Vue.directive(指令名, 配置对象/回调函数)
  • 局部注册:在 Vue 实例的 directives 选项中配置
  • 注意事项:指令名定义时不加 v-,使用时需加 v-;多单词指令采用 kebab-case 命名(如 v-big-number)。
配置对象常用回调
  • bind:指令与元素成功绑定时调用(初始绑定,仅一次)。
  • inserted:指令所在元素插入 DOM 时调用(适合操作 DOM 节点,如获取焦点)。
  • update:指令所在模板重新解析时调用(数据更新时触发)。
实战案例

需求 1:v-big 指令,将绑定数值放大 10 倍后渲染。需求 2:v-fbind 指令,实现 v-bind 功能 + 输入框默认获取焦点。

<div id="root">
  <h2>放大10倍:<span v-big="n"></span></h2>
  <input type="text" v-fbind:value="n">
</div>
<script>
Vue.config.productionTip = false

// 全局自定义指令v-big
Vue.directive('big', {
  bind(el, binding){ el.innerText = binding.value * 10 },
  update(el, binding){ el.innerText = binding.value * 10 }
})

// 全局自定义指令v-fbind
Vue.directive('fbind', {
  bind(el, binding){ el.value = binding.value }, // 绑定初始值
  inserted(el){ el.focus() }, // 元素插入DOM时获取焦点
  update(el, binding){ el.value = binding.value } // 数据更新时同步值
})

new Vue({
  el:'#root',
  data:{ n:1 }
})
</script>

三、Vue 生命周期:实例的完整生命周期

Vue 实例从创建到销毁的整个过程称为生命周期,每个阶段都有对应的钩子函数,允许开发者在特定时机执行操作。

1. 生命周期核心阶段与钩子函数

阶段 钩子函数 核心作用
实例创建 beforeCreate 数据监测、事件初始化前,无法访问 data、methods
实例创建后 created 数据、方法配置完成,未挂载 DOM,无法访问 $el
挂载前 beforeMount 解析模板生成虚拟 DOM,未插入页面(页面显示原始模板)
挂载后 mounted 虚拟 DOM 转为真实 DOM 并插入页面,可操作 DOM(常用)
更新前 beforeUpdate 数据更新,真实 DOM 未同步(数据新、页面旧)
更新后 updated 真实 DOM 已同步,可执行依赖 DOM 的操作
销毁前 beforeDestroy 实例仍可用,执行收尾工作(如清除定时器、解绑事件)
销毁后 destroyed 实例完全销毁,所有绑定、事件、子实例失效

2. 常用钩子函数实战

  • mounted:初始化操作(发送 AJAX 请求、启动定时器、绑定自定义事件)。
  • beforeDestroy:收尾工作(清除定时器、取消订阅、解绑自定义事件)。

<div id="root">
  <h2 :style="{opacity}">Vue生命周期演示</h2>
  <button @click="stop">停止渐变</button>
</div>
<script>
Vue.config.productionTip = false
new Vue({
  el:'#root',
  data:{ opacity:1 },
  methods:{
    stop(){ this.$destroy() } // 销毁Vue实例
  },
  mounted(){
    // 启动定时器,实现渐变效果
    this.timer = setInterval(()=>{
      this.opacity -= 0.01
      if(this.opacity <= 0) this.opacity = 1
    },16)
  },
  beforeDestroy(){
    // 销毁前清除定时器,避免内存泄漏
    clearInterval(this.timer)
    console.log('实例即将销毁,定时器已清除')
  }
})
</script>

3. 完整代码案例:透明度渐变与生命周期监控

<!DOCTYPE html>
<html lang="zh-***">
<head>
  <meta charset="UTF-8">
  <title>Vue生命周期实战</title>
  <script src="https://cdn.jsdelivr.***/npm/vue@2/dist/vue.js"></script>
  <style>
    /* 用于演示v-cloakak解决插值    {{}}闪烁问题(可选) */
    [v-cloak] {
      display: none;
    }
  </style>
</head>
<body>
  <div id="app" v-cloak>
    <!-- 绑定透明度样式,实现渐变效果 -->
    <h2 :style="{ opacity: opacityValue }">Vue生命周期演示:透明度渐变</h2>
    <button @click="opacityValue = 1">重置透明度</button>
    <button @click="destroyVm">销毁实例</button>
    <p>当前透明度:{{ opacityValue.toFixed(2) }}</p>
  </div>

  <script>
    const vm = new Vue({
      el: '#app',
      data: {
        opacityValue: 1 // 透明度初始值(1=完全不透明)
      },
      methods: {
        destroyVm() {
          this.$destroy() // 调用Vue实例的销毁方法
        }
      },
      // 1. 实例创建前:数据和事件未初始化
      beforeCreate() {
        console.log('【beforeCreate】实例创建前');
        console.log('数据是否可访问:', this.opacityValue); // undefined
        console.log('方法是否可调用:', typeof this.destroyVm); // undefined
      },
      // 2. 实例创建后:数据和方法初始化完成,未挂载DOM
      created() {
        console.log('【created】实例创建后');
        console.log('数据是否可访问:', this.opacityValue); // 1(可访问)
        console.log('方法是否可调用:', typeof this.destroyVm); // function(可调用)
        // 此时无法操作DOM($el不存在)
        console.log('DOM是否挂载:', this.$el); // undefined
      },
      // 3. 挂载前:模板解析完成,虚拟DOM生成,未插入页面
      beforeMount() {
        console.log('【beforeMount】挂载前');
        console.log('虚拟DOM是否生成:', this.$el); // 虚拟DOM(未渲染到页面)
        console.log('页面中是否有解析后的内容:', document.querySelector('h2').innerText); 
        // 输出:{{ opacityValue }}(页面仍显示模板语法)
      },
      // 4. 挂载后:虚拟DOM转为真实DOM,插入页面(常用)
      mounted() {
        console.log('【mounted】挂载后');
        console.log('真实DOM是否生成:', this.$el); // 真实DOM元素
        console.log('页面中是否有解析后的内容:', document.querySelector('h2').innerText); 
        // 输出:Vue生命周期演示:透明度渐变(已渲染)
        
        // 启动定时器,实现透明度渐变(核心业务逻辑)
        this.timer = setInterval(() => {
          this.opacityValue -= 0.01;
          if (this.opacityValue <= 0) this.opacityValue = 1; // 循环渐变
        }, 20);
      },
      // 5. 更新前:数据已更新,真实DOM未同步(数据新,页面旧)
      beforeUpdate() {
        console.log('【beforeUpdate】更新前');
        console.log('数据值:', this.opacityValue.toFixed(2));
        console.log('页面值:', document.querySelector('p').innerText.split(':')[1]);
        // 数据值与页面值不一致(页面未更新)
      },
      // 6. 更新后:真实DOM已同步(数据与页面一致)
      updated() {
        console.log('【updated】更新后');
        console.log('数据值:', this.opacityValue.toFixed(2));
        console.log('页面值:', document.querySelector('p').innerText.split(':')[1]);
        // 数据值与页面值一致(页面已更新)
      },
      // 7. 销毁前:实例仍可用,执行收尾工作(常用)
      beforeDestroy() {
        console.log('【beforeDestroy】销毁前');
        console.log('实例是否仍可用:', this.opacityValue); // 1(数据仍可访问)
        // 清除定时器(避免内存泄漏)
        clearInterval(this.timer);
        console.log('定时器已清除');
      },
      // 8. 销毁后:实例完全失效
      destroyed() {
        console.log('【destroyed】销毁后');
        console.log('实例是否仍可用:', this.opacityValue); // 1(数据仍可访问,但修改不会触发更新)
        // 尝试修改数据,页面不会更新
        this.opacityValue = 0.5;
      }
    });
  </script>
</body>
</html>

案例核心解析:生命周期钩子的执行时机与作用

1. 初始化阶段(创建与挂载)

  • beforeCreate:实例刚被创建,数据监测和事件系统未初始化,无法访问datamethods
    • 用途:几乎不用,可做最早期的准备工作。
  • created:数据和方法初始化完成,但 DOM 未挂载($el不存在)。
    • 用途:适合初始化数据、发送 AJAX 请求(无需操作 DOM 的场景)。
  • beforeMount:模板解析完成,虚拟 DOM 生成,但未渲染到页面,页面仍显示模板语法(如{{}})。
    • 用途:可修改数据,但不会触发更新(实际开发中很少用)。
  • mounted:虚拟 DOM 转为真实 DOM 并插入页面,$el可用。
    • 用途:最常用的钩子,适合操作 DOM(如初始化插件)、启动定时器、绑定事件等。

2. 运行阶段(数据更新)

  • beforeUpdate:数据发生变化后触发,此时数据是新的,但页面仍是旧的(未同步)。
    • 用途:可获取更新前的 DOM 状态。
  • updated:页面已根据新数据更新,数据与 DOM 同步。
    • 用途:可执行依赖新 DOM 的操作(如滚动到指定位置),但需避免在此修改数据(可能导致无限循环)。

3. 销毁阶段

  • beforeDestroy:实例即将销毁,仍可访问数据和方法,所有功能正常。
    • 用途:最常用的钩子,执行收尾工作(清除定时器、解绑事件、取消订阅等)。
  • destroyed:实例完全销毁,所有事件监听、子实例失效,修改数据不会触发更新。
    • 用途:几乎不用,可做最终的资源释放。

关键结论与实战技巧

  1. 常用钩子mounted(初始化操作)和beforeDestroy(收尾工作)是日常开发中使用频率最高的两个钩子。
  2. 内存泄漏防范:在beforeDestroy中必须清除定时器、解绑自定义事件等,避免实例销毁后资源仍在占用。
  3. 销毁后特性:实例销毁后,原生 DOM 事件仍有效(如点击按钮的默认行为),但 Vue 的响应式系统失效(修改数据不会更新页面)。
  4. 调试技巧:通过console.log在每个钩子中输出关键信息(如数据、DOM 状态),可直观观察生命周期流转。

3. 生命周期关键说明

  • 销毁实例后,自定义事件失效,但原生 DOM 事件仍有效。
  • 销毁前操作数据不会触发页面更新(生命周期已停止)。
  • 借助 Vue 开发者工具可查看实例是否已销毁。

总结

        本文围绕 Vue 核心知识点展开,从表单数据收集的 v-model 使用技巧,到内置 / 自定义指令的实战应用,再到生命周期的完整解析,覆盖了 Vue 开发的基础核心场景。掌握这些知识点后,你可以轻松应对大部分交互式页面开发需求。

转载请说明出处内容投诉
CSS教程网 » Vue入门到实战(day4):Vue 表单绑定、自定义指令与Vue生命周期(附代码案例)

发表评论

欢迎 访客 发表评论

一个令你着迷的主题!

查看演示 官网购买