(Vue-cli)九、key值,$nextTick,$forceUpdate,自定义指令directive,自定义插件plugin

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>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,284评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,115评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,614评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,671评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,699评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,562评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,309评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,223评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,668评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,859评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,981评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,705评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,310评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,904评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,023评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,146评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,933评论 2 355

推荐阅读更多精彩内容