v-once

用于指定元素或者组件只渲染一次,一般可用作性能优化

<div id="app">
  <!-- 指令: v-once 点击事件后我的子节点内容都没变-->
  <h2 v-once>
    {{ message }}
    <span>数字: {{counter}}</span>
  </h2>

  <!--  点击事件后我会变 -->
  <h1>{{message}}</h1>

  <button @click="changeMessage">改变message</button>
</div>

<script src="https://unpkg.com/vue@next"></script>
<script>
  // 1.创建app
  const app = Vue.createApp({
    data: function () {
      return {
        message: "Hello Vue",
        counter: 100,
      };
    },
    methods: {
      changeMessage: function () {
        this.message = "你好";
        this.counter += 100;
        console.log(this.message, this.counter);
      },
    },
  });

  // 2.挂载app
  app.mount("#app");
</script>

v-model

  1. 主要应用于表单元素或者组件上;

  2. 本质:value 属性和 input 事件的一个合体;

  3. 修饰符:

    1. v-model.lazy:没有 lazy 使用的是 input 事件,使用了 lazy 使用的是 change 事件;
    2. v-model.number:将输入的内容转换成数字;
    3. v-model.trim:自动去掉首位空格;
  4. v-model 原理:内部会根据标签的不同解析出不同的语法,例如:

    1. 文本框会被解析成 value + input 事件;
    2. 复选框会被解析成 checked + change 事件;

v-text

  1. v-text 能展示对应 data 中数据内容,也能在数据基础上做运算;

  2. v-text 会把标签中的内容替换;

<div id="app">
  <h2>aa {{message}} bbb</h2>
  <!-- 内容都替换了 -->
  <h2 v-text="message">aaa</h2>
  <!-- 数据基础上做运算 -->
  <h2 v-text="message+'zzzzzz'"></h2>
</div>

<script src="https://unpkg.com/vue@next"></script>
<script>
  // 1.创建app
  const app = Vue.createApp({
    data: function () {
      return {
        message: "Hello Vue",
      };
    },
  });

  // 2.挂载app
  app.mount("#app");
</script>

v-html

等同于原生的 innerHtml (一旦使用,后边跟的内容一定是可信任的内容)

<div id="app">
  <h2>{{ content }}</h2>
  <h2 v-html="content"></h2>
</div>

<script src="https://unpkg.com/vue@next"></script>
<script>
  // 1.创建app
  const app = Vue.createApp({
    data: function () {
      return {
        content: `<span style="color: red; font-size: 30px;">哈哈哈</span>`,
      };
    },
  });

  // 2.挂载app
  app.mount("#app");
</script>

v-cloak

  1. 这个指令使用在元素上直到关联实例结束编译;

  2. 因为指令生命周期的特殊性,常备用来解决大胡子语法闪烁问题;

  3. 这个指令可以隐藏未编译的 Mustache 标签直到实例准备完毕,和 CSS 规则如 [v-cloak] { display: none } 一起用时;

<style>
  [v-cloak] {
    display: none;
  }
</style>

<div id="app">
  <h2 v-cloak>{{message}}</h2>
</div>

<script src="https://unpkg.com/vue@next"></script>
<script>
  setTimeout(() => {
    // 1.创建app
    const app = Vue.createApp({
      data: function () {
        return {
          message: "Hello Vue",
        };
      },
    });

    // 2.挂载app
    app.mount("#app");
  }, 3000);
</script>

v-pre

  1. 优化型指令,当代码中出现了一个结构中不包含 vue 变量,则不需要 vue 编译,浪费性能,则加上 v-pre,不用 vue 解析;

  2. v-pre 用于跳过元素和它的子元素的编译过程,显示原始的 Mustache 标签;

<div id="app">
  <div v-pre>
    <h2>{{ message }}</h2>
    <p>当前计数: {{ counter }}</p>
    <p>{{}}</p>
  </div>
</div>

<script src="https://unpkg.com/vue@next"></script>
<script>
  // 1.创建app
  const app = Vue.createApp({
    data: function () {
      return {
        message: "Hello Vue",
        counter: 0,
      };
    },
  });

  // 2.挂载app
  app.mount("#app");
</script>

v-memo(新)

  1. 数组里的每个值都与最后一次的渲染相同,那么整个子树的更新将被跳过;

  2. 下面案例中点击改变信息,内容不会更改,因为 v-memonameage 没有发生改变,因此这个节点中即使 height 改变了也不会渲染视图;

<div id="app">
  <div v-memo="[name, age]">
    <h2>姓名: {{ name }}</h2>
    <h2>年龄: {{ age }}</h2>
    <h2>身高: {{ height }}</h2>
  </div>
  <button @click="updateInfo">改变信息</button>
</div>

<script src="https://unpkg.com/vue@next"></script>
<script>
  // 1.创建app
  const app = Vue.createApp({
    data: function () {
      return {
        name: "www",
        age: 18,
        height: 1.88,
      };
    },
    methods: {
      updateInfo: function () {
        this.name = "www";
        this.age = 18;
        this.height = 10000000;
      },
    },
  });

  // 2.挂载app
  app.mount("#app");
</script>

v-if

  1. vue2.x 中:v-for 优先级大于 v-ifvue3.x 中:v-if 的优先级大于 v-for

  2. 有比较大的切换开销,有比较小的初始加载开销 (条件渲染,如果 if 的表达式是 true,则会插入到虚拟 dom 中)

v-show

  1. v-show 只是单纯的控制 display 样式的显示或隐藏;

  2. 有比较大的初始加载开销,比较小的切换开销 (无论条件是 true 还是 false,始终会插入到虚拟 dom 中)

v-for

  1. 语法上 v-for 指令需要使用 item in items 形式的特殊语法,items 是源数据数组并且 item 是数组元素迭代的别名;

  2. 支持循环 Array、Object、number、string (也可以遍历其他 可迭代对象 (Iterable))

HTML
HTML
<div v-for="(item, index) in items"></div>

<div v-for="(val, key) in object"></div>

<div v-for="(val, key, index) in object"></div>

<div v-for="item  in 10"></div> <!--注意循环数字是从1开始->
<div id="app">
  <p v-for="item in createIterator">{{item}}</p>
</div>

<script src="https://unpkg.com/vue@next"></script>
<script>
  // 1.创建app
  const app = Vue.createApp({
    data: function () {
      return {
        createIterator: {
          items: [1, 2, 3],
          *[Symbol.iterator]() {
            for (let item of this.items) {
              yield item;
            }
          },
        },
      };
    },
  });

  // 2.挂载app
  app.mount("#app");
</script>

v-key

最理想的 key 就是这条数据的唯一 id,可以提升虚拟 dom 的编译效率;通常与 v-for 或者表单一起使用;

v-bind

  1. 动态 key:和 es6 一样在 vue 模板时候也可以动态 key 去和 v-bind 进行绑定;

    <button v-bind:[key]="value"></button>
    
    <h2 :[name]="'aaaa'">Hello World</h2>
    
    <img :src="imageSrc" />
    
  2. 展开对象:可以将一组属性定义为对象;

    <div v-bind="{ id: someProp, 'other-attr': otherProp }"></div>
    
  3. class:还支持下面三种形式 ‘对象’,‘数组’,‘数组对象’;

    <!--动态绑定的 class 是可以和普通的 class 同时的使用 -->
    <div :class="{ red: isRed, active: isRed, zz: true }"></div>
    
    <div :class="[classA, classB,"zz"]"></div>
    
    <div :class="[classA, { classB: isB, classC: isC }]"></div>
    
    <h2 :class="['abc', className, isActive? 'active': '']"></h2>
    
  4. style:除了正常写法也支持 ‘对象’‘数组’,要注意如果 key 是类似 ‘font-size’ 属性需要驼峰写法,如果不驼峰写法需要用引号包裹;

    <div :style="{ fontSize: size + 'px' }"></div>
    <div :style="[styleObjectA, styleObjectB, { backgroundColor: 'purple' }]"></div>
    

v-on

  1. 事件处理器的值可以有两种表现形式,内联事件处理器方法事件处理器,是专门用来处理事件的指令,语法糖:v-on 简写为 @

    1. 内联事件处理器:事件被触发时执行的内联 JavaScript 语句 (最通俗理解,调用方法时候有括号,直接使用以声明属性) 实际上是将其执行的是一段 js 代码;
    2. 方法事件处理器:一个指向组件上定义的方法的属性名或是路径 (简单理解直接方法名字)
  2. 常见使用

    <!-- 动态事件 -->
    <button v-on:[event]="doThis"></button>
    
    <!-- 动态事件缩写 -->
    <button @[event]="doThis"></button>
    
    <!-- 对象语法 -->
    <button v-on="{ mousedown: doThis, mouseup: doThat }"></button>
    
    <!-- 一个事件绑定多个方法  -->
    <button @click="one($event), two($event)">Submit</button>
    
  3. 关于 event:在 vue 中使用 也可以将 event 对象会传递进来,在 内联事件处理器方法事件处理器 传递形式不同;

    <div id="app">
        <!-- 1.默认传递event对象 -->
        <button @click="btn1Click">按钮1</button>
        
        <!-- 2.自己的参数和event对象 -->
        <!-- 在模板中想要明确的获取event对象: $event -->
        <button @click="btn3Click('zzz', $event)">按钮3</button>
    </div>
    
    <script src="https://unpkg.com/vue@next"></script>
    <script>
    // 1.创建app
    const app = Vue.createApp({
        methods: {
            // 1.默认参数: event对象
            // 总结: 如果在绑定事件的时候, 没有传递任何的参数, 那么event对象会被默认传递进来
            btn1Click(event) {
                console.log('btn1Click:', event)
            },
    
            // 2.明确参数+event对象
            btn3Click(name, event) {
                console.log('btn3Click:', name, event)
            },
        },
    });
    
    // 2.挂载app
    app.mount("#app");
    </script>
    
  4. 事件修饰符:

    1. .stop:调用 event.stopPropagation() 阻止事件冒泡;
    2. .prevent:调用 event.preventDefault() 阻止默认事件从里到外;
    3. .capture:添加事件侦听器时使用 capture 模式,实现捕获触发事件的机制从外到里;
    4. .self:只会阻止自己身上的行为,使用修饰符时,顺序很重要 (用 @click.prevent.self 会阻止元素本身及其子元素的点击的默认行为,而 @click.self.prevent 只会阻止对元素自身的点击的默认行为)
    5. .{keyAlias}:仅当事件是从特定键触发时才触发回调 (键盘简写)
    6. .once:只触发一次回调;
    7. .left:只当点击鼠标左键时触发;
    8. .right:只当点击鼠标右键时触发;
    9. .middle:只当点击鼠标中键时触发;
    10. .passive{ passive: true } 模式添加侦听器;

面试题

v-if 和 v-for 哪个优先级更高

  1. Vue2v-for 优先于 v-if 被解析;但在 Vue3 中则完全相反,v-if 的优先级高于 v-for

  2. 文档中明确指出永远不要把 v-ifv-for 同时用在同一个元素上,工程项目中也不应该把它们放一起,因为哪怕只渲染列表中一小部分元素,也得在每次重渲染的时候遍历整个列表;

  3. 通常有两种情况下导致我们这样做:

    1. 为了过滤列表中的项目 (比如 v-for=“user in users” v-if=“user.isActive”),建议直接返回过滤后的列表再去渲染列表;
    2. 为了避免渲染本应该被隐藏的列表 (比如 v-for=“user in users” v-if=“isShowUsers”),建议把 v-if 放到外面一层标签上;
  4. vue2 输出的渲染函数:可以看出会先执行循环再判断条件

    HTML
    JavaScript
    <div id="app">
        <!-- 过滤列表中项目 -->
        <div v-for="item in items" :key="item.id" v-if="item.isActive">
            {{ item.name }}
        </div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data() {
                return {
                    items: [
                        { id: 1, name: '张三', isActive: true },
                        { id: 2, name: '李四', isActive: false }
                    ]
                }
            },
        })
        console.log(app.$options.render);
    </script>
    
    // vue2 的渲染函数,先执行循环再判断条件
    ƒ anonymous() {
        with (this) {
            // _l 是 for 循环,首先 v-for 循环
            return _c('div', { attrs: { "id": "app" } }, _l((items), function (item) {
                // 然后再 v-if 判断 isActive
                return (item.isActive)
                    ? _c('div', { key: item.id }, [_v("\n      " + _s(item.name) + "\n    ")])
                    : _e()
            }), 0)
        }
    }
    
  5. vue3 输出的渲染函数:可以看出会先判断条件再执行循环

    HTML
    JavaScript
    <div id="app">
        <!-- 控制台会报错:
            Uncaught TypeError: Cannot read properties of undefined (reading 'isActive')
        -->
        <!-- v-if 的优先级高于 v-for,v-if 执行时调用的变量还不存在,所以控制台报错 -->
        <!-- 
        <div v-for="item in items" :key="item.id" v-if="item.isActive">
            {{ item.name }}
        </div>
        -->
    <!-- 避免了渲染本应该被隐藏的列表 -->
    <div id="app">
        <div v-for="item of items" :key="item.id" v-if="isShowUsers">
            {{ item.name }}
        </div>
    </div>
    <script src="http://unpkg.com/vue@3"></script>
    <script>
        const app = Vue.createApp({
            data() {
                return {
                    isShowUsers: true,
                    items: [
                        { id: 1, name: '张三', isActive: true },
                        { id: 2, name: '李四', isActive: false }
                    ]
                }
            },
        }).mount('#app')
        console.log(app.$options.render);
    </script>
    
    // vue3 的渲染函数,
    (function anonymous() {
        const _Vue = Vue
        return function render(_ctx, _cache) {
            with (_ctx) {
                const {
                    renderList: _renderList,
                    Fragment: _Fragment,
                    openBlock: _openBlock,
                    createElementBlock: _createElementBlock,
                    toDisplayString: _toDisplayString,
                    createCommentVNode: _createCommentVNode
                } = _Vue
    
                // 先判断条件再执行循环
                return isShowUsers
                    ? (_openBlock(true),
                        _createElementBlock(_Fragment, { key: 0 },
                            _renderList(items, (item) => {
                                return (_openBlock(),
                                    _createElementBlock("div",
                                        { key: item.id },
                                        _toDisplayString(item.name),
                                        1 /* TEXT */
                                    )
                                )
                            }), 128 /* KEYED_FRAGMENT */))
                    : _createCommentVNode("v-if", true)
            }
        }
    })
    

v-once 的使用场景有哪些

  1. v-oncevue 的内置指令,作用是仅渲染指定组件或元素一次,并跳过未来对其更新;

  2. 如果有一些元素或者组件在初始化渲染之后不再需要变化,这种情况下适合使用 v-once,这样哪怕这些数据变化,vue 也会跳过更新,是一种代码优化手段,只需要作用的组件或元素上加上 v-once 即可;

  3. vue3.2 之后,又增加了 v-memo 指令,可以有条件缓存部分模板并控制它们的更新,可以说控制力更强了;

  4. 编译器发现元素上面有 v-once 时,会将首次计算结果存入缓存对象,组件再次渲染时就会从缓存获取,从而避免再次计算;

  5. 示例代码:

    html
    JavaScript
    <template>
      <h1 v-once>{{ msg }}</h1>
      <input v-model="msg" />
    </template>
    <script setup>
    import { ref } from "vue";
    const msg = ref("Hello World!");
    </script>
    
    // vue3 的渲染函数
    return (_ctx, _cache) => {
        return (_openBlock(), _createElementBlock(_Fragment, null, [
            // 从缓存获取vnode
            _cache[0] || (
                _setBlockTracking(-1),
                _cache[0] = _createElementVNode("h1", null, [
                    _createTextVNode(_toDisplayString(msg.value), 1 /* TEXT */)
                ]),
                _setBlockTracking(1),
                _cache[0]
            )
            // ...
        ]))
    }
    

v-for 为什么要加 key

为了在比对过程中进行复用

打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

中午好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于前端开发的技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程。

了解更多

目录

  1. 1. v-once
  2. 2. v-model
  3. 3. v-text
  4. 4. v-html
  5. 5. v-cloak
  6. 6. v-pre
  7. 7. v-memo(新)
  8. 8. v-if
  9. 9. v-show
  10. 10. v-for
  11. 11. v-key
  12. 12. v-bind
  13. 13. v-on
  14. 14. 面试题
    1. 14.1. v-if 和 v-for 哪个优先级更高
    2. 14.2. v-once 的使用场景有哪些
    3. 14.3. v-for 为什么要加 key