directives指令--减少DOM操作的重复
指令的作用:主要用于DOM操作
- Vue实例/组件用于数据绑定、事件监听、DOM更新
- Vue指令主要目的就是原生DOM操作
- 减少重复
- ★ 如果某个DOM操作你经常使用,就可以封装为指令。比如事件绑定经常做,那就写成
v-on指令。 - ★如果某个DOM操作比较复杂,也可以封装为指令
Vue自带的指令
请看上一篇博客
自己造一个指令(官方文档)
两种声明方式
方法一:声明一个全局指令
在main.js里
Vue.directives("x",directiveOptions)
方法二:声明一个局部指令
在options里写,只能被那个Vue实例/组件使用
new Vue({
...,
directives:{
"x":directiveOptions
}
})
关于directiveOptions
directiveOptions是个对象,里面有五个函数属性
- ★
bind(el, info, vnode, oldVnode)
-
类似
created,只调用一次,指令第一次绑定到元素时调用。 -
参数都是vue给我们的
①
el:绑定指令的那个元素②
info:是个对象,我们想要的信息基本都在里面③
vnode:虚拟节点④
oldVnode:之前的虚拟节点
- ★
inserted(参数同上)
- 类似
mounted,被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
update(参数同上)
- 类似
updated
componentUpdated(参数同上)
- 用得不多,见文档
- ★
unbind(参数同上)
- 类似
destroyed,当元素要消亡时调用。
例子:写一个v-on的简单的v-on2
new Vue({
directives: {
on2: {
//当元素出现在页面时,会调用bind函数,我把bind函数写成添加事件监听
//bind和inserted都行
bind(el, info) {
//console.log(info); //打印出info,看看我们需要他的哪些信息
el.addEventListener(info.arg, info.value);
},
//添加了事件监听,那就想办法在一定的时机删掉,不然越累积越多
//当元素要消亡时,会调用unbind函数,我把unbind函数写成删除事件监听
unbind(el, info) {
el.removeEventListener(info.arg, info.value);
}
}
},
template: `
<button v-on2:click="f1">点我</button> //button使用了我们写的指令
`,
methods: {
f1() {
console.log("Hi");
}
}
}).$mount("#app");
Mixins混入,就是复制---减少options构造选项的重复
就是把共同的options构造选项复制到需要用的Vue实例/组件里
作用
- 减少重复
- directives的作用是减少DOM操作的重复
- mixins的作用是减少data、methods、钩子的重复
- options里的构造选项都可以先放到一个js文件,之后哪个实例/组件需要就导入并且用mixins使用就行。
智能合并
写在了共同东西里的东西被组件引用了之后,组件还可以覆盖他们,Vue会智能合并
全局的mixins:不推荐
在main.js里写
Vue.mixins({公用的的options选项})
这样所有的组件都会用这个,所以不推荐。
例子
场景描述
- 非完整版Vue,App.vue引用了五个组件
- 假设我们需要在每个组件上添加name和time
- 在这五个组件
created、destroyed时,打出提示,并报出存活时间 - 请问你怎么做? 给每个组件添加data和钩子,共五次 或者使用mixins减少重复
先写组件Child1
- 当child1组件出生就打印出“child1出生了”
- 那就需要个data里面name:child1
- created函数
- 还需要个时间。那就data里面time为出生时间
- 在出生时记录时间(
new Date),给time赋值
- child1组件死亡了就打印出“child1死亡了,共生存了多少ms”
- beforeDestroy
- 获得当前时间
- 那么存活时间就是当前时间-出生时间
//Child.vue
<template>
<div>Child1</div>
</template>
<script>
export default {
data(){
return {
name:"Child1",
time:undefined //time即将用来表示出生时间
}
},
//当这个组件出生了就执行created函数。
created(){
//把出生时间记录下来
this.time=new Date()
console.log(`${this.name}出生了`)
},
//当组件死掉之前,执行这个函数。注意不是死掉之后,死掉之后数据都没了!
beforeDestroy(){
//把死亡时间记录下来
const now = new Date()
console.log(`${this.name}死亡了,共生存了${now-this.time}ms`)
}
}
</script>
- Child1组件出生是当然的,所以created函数自动执行了。那Child1组件怎么消亡呢?
- Child1组件是被App.vue所使用的。所以用App.vue来控制这个组件消亡
- 消亡就是把这个组件不被App.vue所用,就是把组件从DOM树里弄消失
- 在data里Child1Visible:true(默认不消亡)
- 使用这个组件的时候判断一下,如果Child1Visible是false就不出现在DOM树里,就是消亡了。所以点击按钮的时候让Child1Visible变成false就可以控制消亡了。
//App.vue
<template>
<div id="app">
<Child1 v-if="Child1Visible"/> //用Child1Visible判断是否从DOM树里移走也就是死亡
<button @click="Child1Visible=false">x</button> //点击按钮就会让Child1Visible变成false
<Child2/>
<button>x</button>
<Child3/>
<button>x</button>
<Child4/>
<button>x</button>
<Child5/>
<button>x</button>
</div>
</template>
<script>
import Child1 from "./components/Child1.vue";
import Child2 from "./components/Child2.vue";
import Child3 from "./components/Child3.vue";
import Child4 from "./components/Child4.vue";
import Child5 from "./components/Child5.vue";
export default {
name: "App",
data() {
return {
Child1Visible:true //添加Child1Visible,默认不消亡
};
},
components: {
Child1,
Child2,
Child3,
Child4,
Child5
}
};
</script>
<style>
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
Child1组件写好了,那剩下的四个组件呢?
你不会想把上面的操作在做四遍吧?重复就是罪过啊。
关于每个(子)组件的共同操作,可以用mixins
- 新建src/mixins/log.js,把公共的东西(Child1.vue的options)剪切到log.js里面,在导出。
- 但是注意,以前的name:Child1被写死了,可是其他的组件不能用这个名字啊,所以把name:undefined;之后每个组件在自己里面写name:Childx,就会智能覆盖undefined
const log = {}
export default log
- 每个组件如何使用(就是复制就是复制)?先引入,再放到mixins里(就是复制就是复制)。别忘了写name:Childx
//Child1.vue
<template>
<div>Child1</div>
</template>
<script>
import log from "../mixins/log.js";
export default {
data(){
return {
name:"Child1" //智能覆盖log中的name
}
},
mixins:[log] //把公共的复制到我身体里了
}
</script>
关于(父组件)App.vue的操作
- 在App.vue里还是得把每个子组件的操作再做一遍的
<template>
<div id="app">
<Child1 v-if="Child1Visible"/>
<button @click="Child1Visible=false">x</button>
<Child2 v-if="Child2Visible"/>
<button @click="Child2Visible=false">x</button>
<Child3 v-if="Child3Visible"/>
<button @click="Child3Visible=false">x</button>
<Child4 v-if="Child4Visible"/>
<button @click="Child4Visible=false">x</button>
<Child5 v-if="Child5Visible"/>
<button @click="Child5Visible=false">x</button>
</div>
</template>
<script>
import Child1 from "./components/Child1.vue";
import Child2 from "./components/Child2.vue";
import Child3 from "./components/Child3.vue";
import Child4 from "./components/Child4.vue";
import Child5 from "./components/Child5.vue";
export default {
name: "App",
data() {
return {
Child1Visible: true,
Child2Visible: true,
Child3Visible: true,
Child4Visible: true,
Child5Visible: true,
};
},
components: {
Child1,
Child2,
Child3,
Child4,
Child5
}
};
</script>
<style>
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
Extends 继承、扩展
- extends是比mixins更抽象一点的封装
- 如果你嫌写五次mixins麻烦,可以考虑extends一次
- 不过实际工作中用得很少
- 你可以使用Vue.extend或options.extends
const MyVue = Vue . extend({
data(){ return {name: “' ,time:undefined} },
created(){
if( !this . name){ console. error('
no name! ')}
this. time = new
Date( )
},
beforeDestroy(){
const duration = (new Date()) - this. time
console . log( ${ this . name}存活时间$ { duration}^ )
})
然后我们就可以使用new Vue(options)了
provide | inject提供和注入
- 祖先提供东西,后代注入东西
- 作用是大范围、隔N代共享信息(data、methods等)
例子:一键换肤(代码,代码)
- 点击换肤按钮会切换class:${themeName}(blue|red)来切换css从而改变颜色
- 每个子组件都要有换肤按钮
- 那就把换肤按钮也写成一个组件,其他组件导入使用就行了
- 可是themeName是App.vue的data,换肤按钮组件怎么拿到祖先的东西?
- 那就让(祖先)App.vue提供themeName;
(子孙代)换肤按钮组件把themeName注入自己就行
- 但是祖先传过来的themeName到我们这只是我们复制的一个字符串。我们改了我们的字符串themeName并不会改祖先的themeName。所以祖先得写一个可以修改祖先自己的themeName的函数提供给换肤按钮组件,这样换肤按钮组件才可以真的改themeName
例子:选择字体大小
- 点击字体按钮会切换class:${fontSizeName}(normal|big|small)来切换css从而改变字体大小
- 写css:当.app.fontsize-normal ;当.app.fontsize-big ; 当.app.fontsize-small
- App.vue得提供可以修改自己的fontSizeName的函数给按钮组件
总结
directives指令
- 全局用
Vue.directive('x', {...}) - 局部用
options.directives - 作用是减少DOM操作相关重复代码
mixins混入
- 全局用
Vue.mixin({..}) - 局部用
options.mixins: [mixin1, mixin2] - 作用是减少options里的重复
extends继承/扩展
- 全局用
Vue.extend({.}) - 局部用
options.extends: {...} - 作用跟mixins差不多,只是形式不同
provide | inject提供和注入
- 祖先提供东西,后代注入东西 *作用是大范围、隔N代共享信息