美文网首页
(Vue-cli)九、key值,$nextTick,$force

(Vue-cli)九、key值,$nextTick,$force

作者: Jinx要睡懒觉 | 来源:发表于2022-01-05 00:32 被阅读0次

    1.key值

    列表渲染时,key值最好是对象的唯一属性值,比如:学号,工号,身份证号,手机号等等,
    目的是:当列表更新时,提高后期渲染的性能。
    当key值时唯一属性值时,二次渲染时,之前的内容不会更新,而是更新后添加或者更改的内容。

    如下图,当我们在更改原始对象数据时,vue在底层创建了一个虚拟的dom,根据这个key的值来判断,哪些值修改了,哪些值增加了或者删除了,然后在真实的dom中根据修改了或者添加删除了key值的内容进行重新渲染,而并非对整个dom进行重新渲染,这样就大大的节省了性能。


    因为vue在渲染数据时,先将数据生成一份虚拟DOM,再将虚拟DOM生成对应的真实DOM挂载到页面中,
    当vue中的数据修改后,会重新生成一份虚拟DOM,并跟之前的虚拟DOM进行匹配,
    如果两份虚拟DOM中的key和key对应的值完全相同,不会重新生成对应的真实DOM,
    只有key和key对应的值不同的虚拟DOM,才会生成新的真实DOM并挂载到页面中。

    代码体现:

    <template>
      <div class="home">
        <button @click="addEmp">添加员工</button>
        <ul>
          <!-- 如果key是索引index,当位置发生变化时,所有数据都会重新渲染 -->
          <!-- <li v-for="(item, index) in list" :key="index">{{ item }}</li> -->
          <!-- 如果key是唯一值id,当位置发生变化时,只会渲染更新的数据 -->
          <li v-for="(item,index) in employees" :key="item.id">{{ item }}</li>
        </ul>
      </div>
    </template>
    
    <script>
    export default {
      name: "Home",
      data() {
        return {
          // 定义一个工程师数组
          employees: [
            {
              id: 1001,
              name: "刘德华",
              age: 20,
              sex: "男",
            },
            {
              id: 1002,
              name: "张学友",
              age: 21,
              sex: "男",
            },
            {
              id: 1003,
              name: "黎明",
              age: 23,
              sex: "男",
            },
            {
              id: 1004,
              name: "郭富城",
              age: 24,
              sex: "男",
            },
          ],
        };
      },
      methods: {
        // 添加员工的方法
        addEmp() {
          let emp={
            id:Date.now(),   // 返回当前时间的时间戳 确保id唯一
            name:'蔡依林',
            age:22,
            sex:'女'
          }
          // this.employees.push(emp)
          this.employees.unshift(emp)
        },
        
      },
    };
    </script>
    

    2.$nextTick() 方法

    见官方-文档-API
    $nextTick( )方法,需要传一个回调函数,回调函数里面的代码在DOM更新完成后执行。如下所示,当页面的数据更新后,让添加的内容获取焦点。如果不使用则是给添加内容前的最后一个元素让其获取焦点。
    代码体现:

    <template>
      <div class="one">
        <input type="text" v-model="carName" />
        <button @click="addcar">添加汽车</button>
        <ul ref="list">
          <li v-for="item in cars" :key="item.id">
            <input :value="item.name" />
          </li>
        </ul>
      </div>
    </template>
    
    export default {
      name: "One",
      data() {
        return {
          carName: "",
          // 汽车数组
          cars: [
            {
              id: 1001,
              name: "玛莎拉蒂",
            },
            {
              id: 1002,
              name: "布加迪威龙",
            },
          ]
        };
      },
      methods: {
        addcar() {
          let car = {
            id: Date.now(),
            name: this.carName,
          };
          this.cars.push(car);
          this.carName = "";
          // $nextTick方法,需要传一个回调函数,回调函数里面的代码,在DOM更新完成后执行。
          this.$nextTick(() => {
            // 让最后一个li元素获取焦点, focus()方法用于为元素设置焦点。
            this.$refs.list.lastChild.lastChild.focus();
          });
        },
      },
    };
    

    3.$forceUpdate() 方法

    见官方-文档-API
    $forceUpdate(),进行强制更新。调用这个方法会更新视图和数据,触发updated生命周期。

    该方法,迫使vue实例强制更新。如下,当给一个对象,使用下图的方式添加一个属性时,如果单单使用该方法,不是响应式的,dom页面无法渲染,但如果添加this.$forceUpdate( ) 方法的话,则页面会强制更新,但是依然不会响应式的。

    <template>
      <div class="one">
        <button @click="employee.name='蔡依林'">修改姓名</button>
        <button @click="addSex">添加性别</button>
        <div>{{employee}}</div>
      </div>
    </template>
    
    export default {
      name: "One",
      data() {
        return {
          employee: {
              name: "周杰伦",
              age: 20,
          }
        };
      },
      methods: {
        addSex() {
          // this.employee.sex='男'
          // console.log(this.employee);
          // 这时候打印,后台已经有性别男,这个数据了,但是页面没有更新到它
          // 因为VUe在初始化的时候,会把data里的所有属性做一个响应式,而后加的就没有。
          // 如果想要后加的,也具备响应式,就要
          // this.$set(this.employee,'sex','男')
    
          // 直接添加的属性,不具备响应式
          this.employee.sex = "男";
          // $forceUpdate()方法,迫使Vue实例重新渲染
          this.$forceUpdate();
        },
      },
    };
    

    4.自定义指令(directives)

    4.1 定义局部指令

    局部就 直接在某组件内,搞一个 directives:{ }

    指令就是一个方法,方法的第一个参(el)传递的是指令所在的DOM元素,指令的第二个参数是给指令绑定的值(bind),bind是一个对象,里面很多的值,其中value是值
    因此,v-html背后的原理就是如下:
        <div v-red>好好学习</div>
        <p v-red>天天向上</p>
        <div v-html="car"></div>
        <div v-myhtml="car"></div>
    
    export default {
      name: "Two",
      data() {
          return {
              car:'<h2>保时捷卡宴是真滴好看</h2>'
          }
      },
      directives: {
        // 指令就是一个方法,方法的第一个参数el,传递的是指令所在的DOM元素
        // 注册一个局部自定义指令 'v-red',设置字体颜色为红色
        red: function (el) {
          el.style.color = "red";
        },
        // 指令方法的第二个参数bind,是给指令绑定的值
        // 注册一个局部自定义指令 'v-myhtml',渲染html标签数据
        myhtml(el,bind){
          el.innerHTML = bind.value
        }
      },
    };
    

    因此,定义局部指令,所有的指令背后都是在操作DOM,我们将这种功能称之为:造轮子。

    4.2 全局自定义指令

    在src文件夹下新建一个directive文件夹,在其中创建index.js,
    引入vue,然后创建全局自定义指令,
    在全局入口文件main.js中导入该文件。

    // 定义全局自定义指令
    import Vue from 'vue'
    Vue.directive('mycolor',function(el,bind){
        el.style.color = bind.value
    })
    
    // 导入全局自定义指令
    import './directives'
    

    此时在任何页中均可以使用。

    <div v-html="car" v-color="'skyblue'"></div>
    <div v-myhtml="car" v-color="'pink'"></div>
    

    5.自定义插件(plugins)

    见官方-教程

    插件的本质上就是一个对象,该对象中必须包含一个install( ) 方法,方法的第一个参数是Vue,第二个参数是配置对象。install方法,会在use的时候执行,Vue.use(插件名),这里的vue会作为install方法的第一个参数。

    在src文件夹下新建一个plugins文件夹,在其中创建index.js,
    在全局入口文件main.js中导入并use插件,
    使用插件。

    export default {
        install:function(Vue,options){
            // 可以直接给Vue添加成员
            Vue.sayHi = function(){
                console.log('大家好,我是Vue');
            },
            Vue.msg = '欢迎使用插件',
            // 可以在Vue的原型上扩展成员
            Vue.prototype.sayHello = function(){
                console.log('哈哈!我是Vue原型上的方法');
            },
            // 给Vue混入成员
            Vue.mixin({
                data() {
                    return {
                        plane:{
                            name:'奔驰',
                            price:'100w'
                        }
                    }
                },
                methods: {
                    showplane(){
                        console.log(this.plane.name,this.plane.price);
                    }
                },
            }),
            // 注册全局组件
            Vue.component('b-box', {
                // 在脚手架环境中,只能通过渲染函数定义全局组件
                render(h) {
                    return h('div',this.$slots.default)
                },
            }),
            // 注册全局指令
            Vue.directive('bgcolor', function(el,bind){
                el.style.backgroundColor = bind.value
            })
        }
    }
    
    // 导入自定义插件
    import myPlugin from './plugins'
    // 注意:一定要use
    Vue.use(myPlugin)
    
    <!-- 调用插件中定义的vue原型上的方法 -->
    <button @click="sayHello">sayHello</button>
    <!-- 调用插件中定义的vue方法 -->
    <button @click="sayHi">sayHello</button>
    <!-- 调用插件中定义的混入成员 -->
    <button @click="showplane">showplane</button>
    <div v-bgcolor="'lightblue'">我是淡蓝色</div>
    <b-box>哈哈</b-box>
    

    相关文章

      网友评论

          本文标题:(Vue-cli)九、key值,$nextTick,$force

          本文链接:https://www.haomeiwen.com/subject/fmxhcrtx.html