Skip to content

指令

插值语法

mustache

mustache{ {variable} },最基础的数据绑定方式,用于将数据动态渲染为纯文本内容。

  • 语法:

    html
    <div>{{ variable }}</div>
  • 示例:

    html
    <script>
    data() {
      return {
        message: "Hello Vue!",
        count: 42
      };
    }
    </script>
    
    <div>{{ message }}</div>    <!-- 输出:Hello Vue! -->
    <div>{{ count }}</div>      <!-- 输出:42 -->
  • 特性:

  • 响应式:数据变化时,插值内容会自动更新。

  • 支持JS表达式

    html
    <!-- 1. 算术运算 -->
    <div>{{ count + 1 }}</div>         <!-- 输出:43 -->
    <div>{{ count * 2 }}</div>         <!-- 输出:84 -->
    
    <!-- 2. 三元运算符 -->
    <div>{{ count > 0 ? '正数' : '零或负数' }}</div> <!-- 输出:正数 -->
    
    <!-- 3. 方法调用(不推荐) -->
    <div>{{ message.toUpperCase() }}</div> <!-- 输出:HELLO VUE! -->
    
    <!-- 4. 访问对象或数组 -->
    <div>{{ user.name }}</div>       <!-- 输出:Alice -->
    <div>{{ list[0] }}</div>          <!-- 输出:Apple -->
  • 不支持语句和声明

    html
    <!-- 1. 不支持变量声明 -->
    <h2>{{var name = "Hello"}}</h2> <!-- 错误用法 -->
    
    <!-- 2. 不支持流程控制语句if -->
    <h2>{{ if (true) { return message } }}</h2> <!-- 错误用法 -->
  • HTML转义:mustache语法会将内容中的HTML标签自动转义为纯文本,避免 XSS 攻击。

    html
    <div>&lt;span&gt;危险内容&lt;/span&gt;</div> <!-- 转义后结果 -->
  • 不能用于HTML属性:mustache语法不能直接用于HTML属性,需改用 v-bind。

    html
    <div id="{{ dynamicId }}"></div> <!-- 错误用法 -->
    <div v-bind:id="dynamicId"></div> <!-- 正确用法 -->
  • 不推荐方法调用:mustache中调用方法是合法的,但是只推荐逻辑简单且无副作用的方法,复杂逻辑的方法推荐使用computed计算属性。

    html
    <div>{{ reversedMessage }}</div> <!-- 输出:!euV olleH -->
    js
    computed: {
      reversedMessage() {
        return this.message.split('').reverse().join('');
      }
    }
  • 结合过滤器

    • 在 Vue2 中,可通过过滤器格式化内容。
    • 在 Vue3 中已经废弃了过滤器,推荐使用计算属性或方法。
    html
    <div>{{ message | capitalize }}</div>
    js
    filters: {
      capitalize(value) {
        return value.charAt(0).toUpperCase() + value.slice(1);
      }
    }
  • 空白内容处理:如果绑定的值为 null 或 undefined,Mustache 会渲染为空字符串。

    html
    <div>{{ undefinedValue }}</div> <!-- 输出空白 -->
  • 闪烁问题:在未编译完成时,原始 { { } } 可能短暂显示。可以添加v-cloak并通过 CSS 隐藏未编译的模板。

    html
    <div v-cloak>{{ message }}</div>
    css
    [v-cloak] { display: none; }

文本渲染

v-text

v-textdataProperty,用于将数据作为纯文本动态渲染到元素中。

  • dataProperty基本类型,绑定的数据可以是字符串、数字或其他基本类型,非字符串类型会自动转换为字符串。

  • 示例:

    html
    <div v-text="message"></div>  <!-- 输出:Hello Vue! -->
    <div v-text="count"></div>    <!-- 输出:42 -->
    js
    data() {
      return {
        message: "Hello Vue!", // 字符串
        count: 42 // 数字
      };
    }
  • 特性:

  • 覆盖行为

    • v-text 会替换目标元素的全部内容,包括子元素。
    • Mustache 仅替换插值标记位置的内容。
    html
    <!-- 1. 使用 v-text -->
    <div v-text="content">原始内容会被覆盖</div>
    <!-- 渲染结果:<div>动态内容</div> -->
    
    <!-- 2. 使用 Mustache -->
    <div>原始内容 {{ dynamicPart }} 保留</div>
    <!-- 渲染结果:<div>原始内容 动态部分 保留</div> -->
  • 转义行为

    • v-text 会将内容中的 HTML 标签转义为纯文本,防止 XSS 攻击。
    • v-html 会解析数据中的 HTML 标签并渲染。
    html
    <div>&lt;script&gt;alert(1)&lt;/script&gt;</div> <!-- v-text转义后结果 -->
  • 动态绑定:可绑定计算属性、方法返回值或复杂表达式。

    html
    <div v-text="message.toUpperCase()"></div> <!-- 方法 -->
    <div v-text="user.name + '的年龄:' + user.age"></div> <!-- 表达式 -->
  • 闪烁问题:v-text 不存在闪烁问题。

  • 性能优化:对于复杂逻辑,优先使用计算属性而非直接在模板中调用方法。

    html
    <!-- 推荐 -->
    <div v-text="formattedDate"></div>
    
    <!-- 不推荐 -->
    <div v-text="formatDate(timestamp)"></div>
  • 指令冲突:避免在同一元素上同时使用 v-text 和 v-html,或与其他内容类指令混用。

v-html

v-htmldataProperty,用于将数据作为原始 HTML 解析并渲染到元素中。

  • dataPropertyHTMLString,包含有效的 HTML 的字符串。

  • 语法:

    html
    <div v-html="rawHtml"></div>
  • 示例:

    html
    <!-- 模板中使用 -->
    <div v-html="rawHtml"></div> 
    
    <!-- Vue 实例或组件 -->
    <script>
    data() {
      return {
        rawHtml: '<span style="color: red;">红色文字</span>'
      };
    }
    </script>
    
    <!-- 渲染结果 -->
    <div>
      <span style="color: red;">红色文字</span>
    </div>
  • 特性:

  • 对比mustache

    • mustache 会将数据解释为纯文本,直接输出 HTML 标签的源代码。
    • v-html 会解析数据中的 HTML 标签并渲染。
    html
    <div>&lt;span style="color: red;"&gt;红色文字&lt;/span&gt;</div> <!-- mustache渲染结果 -->
    
    <div><span style="color: red;">红色文字</span></div> <!-- v-html渲染结果 -->
  • 动态绑定:v-html 可以绑定动态值,如计算属性、方法返回值等。

    html
    <div v-html="dynamicHTML"></div>
    
    <script>
    computed: {
      dynamicHTML() {
        return this.isError ? '<p class="error">错误信息</p>' : '<p>正常信息</p>';
      }
    }
    </script>
  • XSS攻击

    • v-html 会直接渲染任意 HTML,如果内容来自用户输入或不可信来源,可能导致XSS跨站脚本攻击。需仅渲染可信内容,如后端返回的已消毒的富文本。

      html
      <div v-html="userProvidedContent"></div> <!-- 危险! -->
    • 替代方案:如果需要渲染部分用户输入,可以使用第三方库DOMPurify消毒。

      js
      import DOMPurify from 'dompurify';
      
      data() {
        return {
          userContent: DOMPurify.sanitize(untrustedHTML)
        };
      }
  • 指令冲突:避免在同一元素上同时使用 v-text 和 v-html,或与其他内容类指令混用。

v-pre

v-pre,用于跳过指定元素及其子元素的编译过程,直接保留原始内容。

  • 语法:

    html
    <div v-pre>
      <!-- 内部内容不会被 Vue 编译 -->
    </div>
  • 示例:

    html
    <template>
      <div>
        <!-- 使用 v-pre 展示源码 -->
        <pre v-pre>
          &lt;div&gt;{{ message }}&lt;/div&gt;
          &lt;button @click="show = true"&gt;显示&lt;/button&gt;
        </pre>
      </div>
    </template>
  • 特性:

  • 跳过编译

    • v-pre 会跳过元素及其所有子元素的 Vue 模板编译过程,直接保留原始内容。
    • 即使内容包含 Vue 语法,如 { { } } 或指令,也会直接显示为文本。
  • 作用范围:v-pre 会影响整个元素及其子元素,无法局部禁用编译。若需部分跳过编译,需拆分元素结构。

  • 与动态内容冲突:在 v-pre 区域内,所有 Vue 功能如数据绑定、指令均失效。

  • 性能影响:仅在需要时使用 v-pre,过度使用可能导致模板编译优化机会减少。

绑定

v-bind

v-bind表达式,用于动态绑定HTML属性、组件prop或DOM属性到Vue实例的数据。

  • 语法:

    html
    <!-- 绑定单个属性 -->
    <div v-bind:属性名="表达式"></div>
    
    <!-- 简写形式(推荐) -->
    <div :属性名="表达式"></div>
  • 示例:

    html
    <a :href="url">Vue 官网</a>
    <button :disabled="!isActive">提交</button>
  • 特性:

  • 动态参数

    • 绑定动态参数:通过 [] 语法动态指定绑定的属性名。

      html
      <div :[attrName]="123"></div>
      <!-- 渲染结果:<div data-id="123"></div> -->
      js
      data() {
        return { attrName: "data-id" }
      }
    • 动态参数限制:动态属性名需为字符串,且避免使用大写或特殊字符(空格/引号)。当使用DOM内嵌模板(直接写在HTML文件里的模板),浏览器会强制将其转换为小写。

      html
      <!-- 错误示例 -->
      <div :[dynamicAttr]="value"></div> <!-- HTML模板中会被转换为:[dynamicattr] -->
  • 批量绑定属性:直接绑定一个对象,键为属性名,值为对应数据。

    html
    <div v-bind="attrs"></div>
    <!-- 渲染结果:<div id="container" class="main" data-status="active"></div> -->
    js
    data() {
      return {
        attrs: {
          id: "container",
          class: "main",
          "data-status": "active"
        }
      };
    }
  • 绑定class

    • 对象语法:根据条件动态切换类名。

      html
      <div :class="{ active: isActive, 'text-red': hasError }"></div>
    • 数组语法:绑定多个类名。

      html
      <div :class="[baseClass, isActive ? 'active' : '']"></div>
  • 绑定style

    • 对象语法:绑定内联样式对象。CSS属性名可以是camelCase,也可以是kebab-case的写法。

      html
      <div :style="{ color: textColor, fontSize: fontSize + 'px' }"></div>
    • 数组语法:应用多个样式对象。CSS属性名可以是camelCase,也可以是kebab-case的写法。

      html
      <div :style="[baseStyles, overrides]"></div>
  • 组件prop传递:在组件上使用v-bind可批量传递props。

    html
    <child-component v-bind="propsObj"></child-component>
  • Vue3变化

    • 移除.sync修饰符:Vue3中废弃.sync,改用v-model参数实现双向绑定。

      html
      <!-- Vue 2 -->
      <ChildComponent :title.sync="pageTitle" />
      
      <!-- Vue 3 -->
      <ChildComponent v-model:title="pageTitle" />
    • 合并行为:当同时使用普通属性和v-bind绑定时,后者会覆盖前者。

      html
      <div id="static" :id="dynamicId"></div>
      <!-- 渲染结果:<div id="dynamic"></div> -->

v-on

v-on表达式,用于监听 DOM 事件或自定义事件,并执行对应的 JavaScript 代码或方法。

  • 语法:

    html
    <!-- 监听事件并执行表达式 -->
    <div v-on:事件名="表达式"></div>
    
    <!-- 简写形式(推荐) -->
    <div @事件名="表达式"></div>
  • 示例:

    html
    <button @click="count += 1">点击增加</button>
    <button @mouseover="showTooltip = true">悬停提示</button>
  • 特性:

  • 绑定方法:将事件直接绑定到组件中定义的方法。

    html
    <button @click="handleClick">提交</button>
    js
    methods: {
      handleClick() {
        console.log("按钮被点击");
      }
    }
  • 传递参数

    • 手动传递参数

      html
      <button @click="handleDelete(item.id)">删除</button>
      js
      methods: {
        handleDelete(id) {
          this.items = this.items.filter(item => item.id !== id);
        }
      }
    • 获取原生事件对象$event:当需要同时传递参数和原生事件对象时,显式传递 $event

      html
      <button @click="handleSubmit('参数', $event)">提交</button>
      js
      methods: {
        handleSubmit(arg, event) {
          event.preventDefault();
          console.log("参数:", arg);
        }
      }
  • 事件修饰符:Vue 提供了事件修饰符,用于简化常见的事件处理逻辑。

    • .stop:阻止事件冒泡,等价于 event.stopPropagation()
    • .prevent:阻止默认行为,等价于 event.preventDefault()
    • .capture:使用事件捕获模式,从外到内触发。
    • .self:仅当事件从元素本身触发时(非子元素)才执行回调。
    • .once:事件只触发一次,Vue3 中也可用于组件事件。
    • .passive:表示不阻止默认行为。提升滚动性能,与 addEventListener 的 passive 选项一致。慎用,不可与 .prevent 同时使用。
    • .native:监听原生事件(Vue3已废弃)。
    html
    <!-- 阻止表单默认提交和事件冒泡 -->
    <form @submit.prevent.stop="onSubmit"></form>
    
    <!-- 点击事件最多触发一次 -->
    <button @click.once="handleOnce">仅一次</button>
    
    <!-- 滚动事件使用 passive 修饰符优化性能 -->
    <div @scroll.passive="onScroll"></div>
  • 按键修饰符:用于监听特定键盘按键的事件,如 Enter、Esc 等。

    • 常用按键别名

      html
      <input @keyup.enter="submit" />      <!-- 回车键 -->
      <input @keyup.esc="closeModal" />    <!-- Esc 键 -->
      <input @keyup.space="playPause" />   <!-- 空格键 -->
      <input @keyup.delete="clearInput" />  <!-- 删除键 -->
    • 自定义按键码:按键码keyCode,Vue 2 支持,Vue 3 已废弃。

      html
      <input @keyup.13="submit" /> <!-- Vue2 中支持 -->
    • 组合键修饰符

      html
      <input @keyup.ctrl.enter="save" />   <!-- Ctrl + Enter -->
      <input @keyup.alt.s="save" />        <!-- Alt + S -->
  • 动态事件名:通过动态属性名绑定不同事件。

    html
    <button @[eventName]="handleEvent"></button>
    js
    data() {
      return {
        eventName: "click"
      };
    }
  • 在组件上监听自定义事件:用于父子组件通信,通过 $emit 触发。

    html
    <!-- 父组件监听子组件的自定义事件 -->
    <ChildComponent @custom-event="handleCustomEvent" />
    js
    // 子组件触发事件
    this.$emit("custom-event", arg1, arg2);
  • 避免内联复杂表达式:推荐将逻辑封装到方法中,而非直接在模板中编写复杂表达式。

    html
    <!-- 不推荐 -->
    <button @click="count += 1; logCount()">增加</button>
    
    <!-- 推荐 -->
    <button @click="handleIncrement">增加</button>

v-model@

v-model表达式,用于在表单输入元素或自定义组件上实现双向数据绑定,是 v-bind 和 v-on 的语法糖。

  • 语法:

    html
    <!-- 基础用法 -->
    <input v-model="dataProperty" />
    
    <!-- 等价于手动绑定 -->
    <input 
      :value="dataProperty" 
      @input="dataProperty = $event.target.value" 
    />
  • 特性:

  • 响应式:表单输入的值与 Vue 实例中的 dataProperty 保持同步。

  • 不同类型表单元素的使用

    • 文本输入:input[type=text]和textarea

      html
      <input type="text" v-model="message" />
      <textarea v-model="content"></textarea>
    • 复选框

      • 单个复选框:绑定布尔值。

        html
        <input type="checkbox" v-model="isAgreed" /> 同意协议
      • 多个复选框:绑定数组。

        html
        <input type="checkbox" value="vue" v-model="skills" /> Vue
        <input type="checkbox" value="react" v-model="skills" /> React
        js
        data() { return { skills: [] }; }
    • 单选按钮

      html
      <input type="radio" value="male" v-model="gender" /> 男
      <input type="radio" value="female" v-model="gender" /> 女
      js
      data() { return { gender: "" }; }
    • 下拉选择

      • 单选

        html
        <select v-model="selectedCity">
          <option value="bj">北京</option>
          <option value="sh">上海</option>
        </select>
      • 多选

        html
        <select v-model="selectedTags" multiple>
          <option value="tag1">标签1</option>
          <option value="tag2">标签2</option>
        </select>
  • 修饰符

    • .lazy:将 input 事件改为 change 事件,输入完成后才同步数据。
    • .number:自动将输入值转为数字类型,避免字符串转换问题。
    • .trim:自动去除输入值首尾空格。
    html
    <!-- 输入完成后同步 -->
    <input v-model.lazy="message" />
    
    <!-- 强制转为数字 -->
    <input type="number" v-model.number="age" />
    
    <!-- 去除首尾空格 -->
    <input v-model.trim="username" />
  • 在自定义组件中使用

    • Vue2 的实现:默认使用 value 属性 和 input 事件。

      html
      <!-- 父组件 -->
      <CustomInput v-model="inputValue" />
      
      <!-- 子组件 -->
      <input 
        :value="value" 
        @input="$emit('input', $event.target.value)" 
      />
      js
      // 子组件声明
      props: ["value"],
    • Vue3 的改进

      • 默认使用 modelValue prop 和 update:modelValue 事件。

        html
        <!-- 父组件 -->
        <CustomInput v-model="count"/>
        
        <!-- 等价于以下写法 -->
        <CustomInput :modelValue="count" @update:modelValue="count = $event"/>
        html
        <!-- 子组件 -->
        <template>
          <button @click="hdlUpdateCount">修改Count</button>
        </template>
        
        <script setup>
          const props = defineProps({
            modelValue: {
              type: Number,
              default:0
            }
          })
          const emit = defineEmits(['update:modelValue'])
          function hdlUpdateCount() {
            emit('update:modelValue', 999)
          }
        </script>
      • 支持自定义参数名(多个双向绑定)。

        html
        <!-- 父组件 -->
        <CustomInput v-model:title="pageTitle" v-model:content="pageContent"  />
        
        <!-- 等价于以下写法 -->
        <CustomInput
          :title="pageTitle" @update:title="pageTitle = $event"
          :content="pageContent" @update:content="pageContent = $event"
        />
        html
        <!-- 子组件 -->
        <template>
          <button @click="hdlUpdateTitle">修改Title</button>
          <button @click="hdlUpdateContent">修改Content</button>
        </template>
        
        <script setup>
          const props = defineProps({
            title: {
              type: String,
              default: ''
            }
            content: {
              type: String
              default: ''
            }
          })
          const emit = defineEmits(['update:title', 'update:content'])
          function hdlUpdateTitle() {
            emit('update:title', '修改后的标题')
          }
          function hdlUpdateContent() {
            emit('update:content', '修改后的内容')
          }
        </script>
    • 修改默认行为:通过组件的 model 选项(Vue2)或 v-model 参数(Vue3)自定义.

      js
      // Vue 2 自定义 prop 和事件
      model: {
        prop: "selected",
        event: "change"
      }

条件渲染

v-show

v-show布尔表达式,用于通过切换 CSS 的 display 属性来控制元素的显示与隐藏。

  • 语法:

    html
    <div v-show="布尔表达式"></div>
  • 示例:

    html
    <div v-show="isVisible">此内容会根据 isVisible 显示/隐藏</div>
    js
    data() {
      return { isVisible: true } 
    }
  • 特性:

  • 实现原理

    • 当表达式为 true 时:移除元素的 display: none 样式。 当表达式为 false 时:添加内联样式 display: none
  • 对比v-if

    • DOM操作

      • v-show:始终保留元素,仅切换 display。
      • v-if:条件为假时移除元素。
    • 初始渲染开销

      • v-show:较高,无论条件如何都渲染元素。
      • v-if:较低,条件为假时不渲染。
    • 切换开销

      • v-show:较低,仅修改 CSS。
      • v-if:较高,触发组件销毁 / 重建。
    • 适用场景

      • v-show:频繁切换显示状态,如选项卡。
      • v-if:条件很少变化,如一键展开 / 收起。
  • 不支持<template>元素:v-show必须作用在实际渲染的DOM元素上,不可用于 <template>

    html
    <!-- 错误用法 -->
    <template v-show="condition">
      <div>内容</div>
    </template>
    
    <!-- 正确用法 -->
    <div v-show="condition">
      <div>内容</div>
    </div>

v-if、v-else、v-else-if

v-if、v-else、v-else-if条件表达式,用于实现条件渲染,根据表达式的真假动态控制元素的渲染或销毁。元素会从DOM中移除。

  • 语法:

    html
    <div v-if="条件表达式"></div>
    <div v-else-if="条件表达式"></div>
    <div v-else></div>
  • 示例:

    html
    <div v-if="score >= 90">优秀</div>
    <div v-else-if="score >= 80">良好</div>
    <div v-else-if="score >= 60">及格</div>
    <div v-else>不及格</div>
  • 特性:

  • 条件链必须连续:指令链必须严格遵循 v-ifv-else-ifv-else 的顺序,中间不能插入其他元素。

  • 控制组件/元素的销毁与重建:v-if 为 false 时,元素及其子组件会被销毁并移出 DOM。频繁切换性能会有影响。

  • 结合<template>:使用 <template> 包裹多个元素实现分组条件渲染。

    html
    <template v-if="showSection">
      <h1>标题</h1>
      <p>内容</p>
    </template>
    <template v-else>
      <div>替代内容</div>
    </template>
  • 状态不保留

    • v-if 为 false 时,元素内部状态(如表单输入值)会被销毁,重新渲染时重置。

    • 解决方案:使用 <keep-alive> 包裹元素以缓存状态。

      html
      <keep-alive>
        <component v-if="isActive"></component>
      </keep-alive>
  • 异步组件:若条件依赖异步数据,需确保数据加载完成后再渲染。

    html
    <div v-if="!isLoading && data">
      {{ data.content }}
    </div>

列表渲染

v-for

v-for表达式,用于基于数据源(数组、对象、数值范围)循环渲染多个元素或组件。

  • 语法:

    html
    <元素 v-for="(item, index?) in data" :key="唯一标识">
      {{ item.attr }}
    </元素>
  • itemany,当前遍历的元素值,数组项 / 对象属性值 / 数值。

  • index?string | number,当前项的索引或键名。

  • dataany,支持数组、对象、数值范围。

  • :keyany,用于标识元素唯一性,优化虚拟DOM的更新性能。

  • 特性:

  • 遍历不同类型数据源

    • 遍历数组

      html
      <ul>
        <li v-for="(item, index) in items" :key="item.id">
          {{ index + 1 }}. {{ item.name }} <!-- 输出:1. Apple-->
        </li>
      </ul>
      js
      data() {
        return {
          items: [
            { id: 1, name: "Apple" },
            { id: 2, name: "Banana" }
          ]
        };
      }
    • 遍历对象

      html
      <ul>
        <li v-for="(value, key, index) in obj" :key="key">
          {{ index }}. {{ key }}: {{ value }} <!-- 输出:0. title: Vue 教程-->
        </li>
      </ul>
      js
      data() {
        return {
          obj: { 
            title: "Vue 教程", 
            author: "John" 
          }
        };
      }
    • 遍历数值范围

      html
      <span v-for="n in 5" :key="n">{{ n }} </span> <!-- 输出:1 2 3 4 5 -->
  • :key

    • 作用

      • 唯一标识:帮助 Vue 识别元素身份,避免重复渲染或状态错乱。
      • 性能优化:基于 key 复用已有 DOM 节点,减少不必要的重新渲染。
    • 用法

      • 唯一性:使用稳定且唯一的标识,如 item.id,避免用索引 index

        html
        <!-- 错误:用索引作为 key -->
        <div v-for="(item, index) in list" :key="index">
          {{ item.name }}
        </div>
  • 结合v-if:v-for 的优先级高于 v-if(Vue2)。若需先判断条件再循环,可将 v-if 置于外层元素。

    html
    <!-- 正确写法 -->
    <template v-if="hasData">
      <div v-for="item in list" :key="item.id">
        {{ item.name }}
      </div>
    </template>
  • 结合计算属性:推荐使用计算属性过滤数据,而非在模板中直接操作。

    html
    <div v-for="item in filteredList" :key="item.id">{{ item.name }}</div>
    js
    computed: {
      filteredList() {
        return this.list.filter(item => item.isActive);
      }
    }
  • 性能优化

    • 避免超大列表:对超长列表(如1000+项)使用虚拟滚动技术,如 vue-virtual-scroller

    • 减少响应式依赖:对不需要响应式的静态数据,使用 Object.freeze 冻结。

      js
      data() {
        return {
          list: Object.freeze([...]) // 禁止 Vue 追踪其变化
        };
      }
    • 扁平化数据结构:避免嵌套过深的响应式对象,优先使用扁平化数据。

  • 在组件中使用

    • 传递 Props:在组件上使用 v-for 时,需显式传递数据。

      html
      <ChildComponent 
        v-for="item in list" 
        :key="item.id"
        :item="item"
        @custom-event="handleEvent"
      />
    • 组件状态保留:若组件需要保留内部状态(如输入框内容),需确保 :key 唯一且稳定。

      html
      <UserInput 
        v-for="user in users" 
        :key="user.id" 
        :user="user" 
      />

key@

key唯一标识,用于标识虚拟 DOM 节点身份的特殊属性,它在 Vue 的响应式更新机制中起到优化渲染性能维护组件状态的关键作用。

  • 语法:

    html
    <元素 :key="唯一标识符"></元素> <!-- 在元素上绑定 key -->
    <组件 :key="唯一标识符"></组件> <!-- 在组件上绑定 key -->
  • 唯一标识

    • 唯一性:同一父级下,每个 key 必须唯一,不可重复。
    • 稳定性:key 值应在数据变化时保持稳定,如id而非index。
  • 特性:

  • 核心作用

    • 优化虚拟DOM对比(Diff 算法):Vue 通过 key 识别节点身份,减少不必要的 DOM 操作。
      • 相同 key:复用现有节点,仅更新变化部分。
      • 不同 key:销毁旧节点,创建新节点。
    • 维护组件/元素状态:当元素或组件因为如列表重新排序而数据变化被复用时,key 可确保其内部状态如输入框内容、滚动位置不被意外保留。
  • 应用场景

    • v-for列表渲染:在 v-for 循环中,每个元素必须绑定唯一 key。

    • 强制替换元素/组件:当需要完全替换元素或组件而非复用,如切换表单类型,可通过改变key强制重新渲染。

      html
      <!-- 切换登录方式时,清空输入框 -->
      <div v-if="isEmailLogin">
        <input key="email" placeholder="邮箱">
      </div>
      <div v-else>
        <input key="phone" placeholder="手机号">
      </div>
    • 动态组件强制刷新:为 <component> 绑定key,避免组件复用导致的生命周期钩子未触发。

      html
      <component :is="currentComponent" :key="currentComponent"></component>
    • 过渡动画强制刷新:确保过渡动画在元素身份变化时正确触发。

      html
      <transition>
        <div :key="state">{{ state }}</div>
      </transition>
  • 底层原理

    • 虚拟DOM Diff过程
      • 无key:Vue 采用 “就地更新” 策略,按索引顺序对比节点,可能导致错误复用。
      • 有key:通过 key 精准匹配相同节点,最小化 DOM 操作。
    • 状态保留机制
      • 相同key:复用元素,保留表单值、滚动位置等状态。
      • 不同key:销毁旧元素,初始化新元素。

其他

v-once

v-once,用于标记元素或组件仅渲染一次,后续数据变化时不再更新。

  • 语法:

    html
    <元素 v-once>{{ 静态内容 }}</元素> <!-- 元素上使用 -->
    <组件 v-once></组件> <!-- 组件上使用 -->
  • 示例:

    html
    // 首次渲染后冻结组件
    <template>
      <UserProfile v-once :initialData="userData" /> <!-- 用户资料不再更新 -->
    </template>
  • 特性:

  • 核心作用

    • 单次渲染:初始渲染后,元素/组件及其子内容不再响应数据变化。
    • 性能优化:减少不必要的虚拟 DOM 比对,提升渲染效率。
  • 使用场景

    • 静态内容优化

      html
      <!-- 标题永不更新 -->
      <h1 v-once>{{ initialTitle }}</h1>
    • 复杂计算的缓存

      html
      <!-- 计算密集型数据只计算一次 -->
      <div v-once>{{ heavyCompute(data) }}</div>
    • 避免子组件更新

      html
      <!-- 父组件数据变化时,子组件不更新 -->
      <ChildComponent v-once :prop="staticData" />
  • 作用范围:影响整个元素及其子树,包括子组件。若子组件依赖动态 props,v-once 会阻止其更新。

v-cloak

v-cloak,用于在 Vue 实例完成编译前隐藏未编译的模板内容,避免页面加载时出现原始模板符号({ { } })的短暂闪烁。必需配合 CSS 样式,CSS 必须全局生效

  • 语法:

    html
    <!-- 在根元素或需要隐藏的元素上添加 v-cloak -->
    <div v-cloak>{{ message }}</div>
    css
    /** CSS 必须全局生效 */
    [v-cloak] {
      display: none !important;
    }
  • 示例:

    html
    <!DOCTYPE html>
    <html>
    <head>
      <style>
        [v-cloak] {
          display: none;
        }
      </style>
    </head>
    <body>
      <div id="app" v-cloak>
        <p>{{ message }}</p>
      </div>
    
      <script src="https://unpkg.com/vue@3"></script>
      <script>
        Vue.createApp({
          data() {
            return { message: "Hello Vue!" };
          }
        }).mount('#app');
      </script>
    </body>
    </html>
  • 特性:

  • 实现原理

    • 初始阶段:元素带有 v-cloak 属性,CSS 将其隐藏。
    • 编译完成:Vue 移除所有 v-cloak 属性,元素显示渲染后的内容。
  • 配合异步加载:若 Vue 实例异步加载,如按需加载,v-cloak 仍可确保内容隐藏直至编译完成。

    html
    <div v-cloak>
      <p v-if="loaded">{{ data }}</p>
    </div>