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

2022-01-05  本文已影响0人  Jinx要睡懒觉

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>
上一篇下一篇

猜你喜欢

热点阅读