- 指令Direvtives
- directiveOptions的属性
- 指令的作用
- 混入 mixins
- 继承extends
- 提供 provide 和 注入 inject
- provide 和 inject总结
-曾老湿, 江湖人称曾老大。
-多年互联网运维工作经验,曾负责过大规模集群架构自动化运维管理工作。 -擅长Web集群架构与自动化运维,曾负责国内某大型金融公司运维工作。 -devops项目经理兼DBA。 -开发过一套自动化运维平台(功能如下): 1)整合了各个公有云API,自主创建云主机。 2)ELK自动化收集日志功能。 3)Saltstack自动化运维统一配置管理工具。 4)Git、Jenkins自动化代码上线及自动化测试平台。 5)堡垒机,连接Linux、Windows平台及日志审计。 6)SQL执行及审批流程。 7)慢查询日志分析web界面。
指令Direvtives
如何自己造一个指令 |
---|
之前我们学习了很多指令,v-if、v-for、v-on、v-bind...等等都是指令
那么今天,我们就来自己造一个指令出来 目标:造出v-x指令,点击即出现一个x
写法一:全局指令
代码语言:javascript复制Vue.directive('x',directiveOptions)
// 你就可以在任意组件中使用v-x了。
写法二:局部指令
代码语言:javascript复制new Vue({
...,
directives:{
"x":directiveOptions
}
})
// v-x只能在该实例中使用
全局指令 |
---|
main.js
代码语言:javascript复制import Vue from "vue";
import App from "./App.vue";
Vue.config.productionTip = false;
Vue.directive('x',{
inserted:function(el){
el.addEventListener('click',()=>{console.log('x')})
}
})
new Vue({
render: h => h(App)
}).$mount('#app')
App.vue
代码语言:javascript复制<template>
<div id="app">
<img v-x width="25%" src="./assets/logo.png">
<HelloWorld msg="Hello Vue in CodeSandbox!" />
</div>
</template>
<script>
import HelloWorld from "./components/HelloWorld";
export default {
name: "App",
components: {
HelloWorld
}
};
</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>

菊部指令 |
---|
只能在Helloworld组件中使用
HelloWorld.vue
代码语言:javascript复制<template>
<div class="hello">
<h1 v-x>{{ msg }}</h1>
<h3>Installed CLI Plugins</h3>
<ul>
<li>
<a
href="https://github.com/vuejs/vue-cli/tree/dev/packages/@vue/cli-plugin-babel"
target="_blank"
rel="noopener"
>babel</a>
</li>
<li>
<a
href="https://github.com/vuejs/vue-cli/tree/dev/packages/@vue/cli-plugin-eslint"
target="_blank"
rel="noopener"
>eslint</a>
</li>
</ul>
<h3>Essential Links</h3>
<ul>
<li>
<a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a>
</li>
<li>
<a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a>
</li>
<li>
<a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a>
</li>
<li>
<a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a>
</li>
<li>
<a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a>
</li>
</ul>
<h3>Ecosystem</h3>
<ul>
<li>
<a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a>
</li>
<li>
<a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a>
</li>
<li>
<a
href="https://github.com/vuejs/vue-devtools#vue-devtools"
target="_blank"
rel="noopener"
>vue-devtools</a>
</li>
<li>
<a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a>
</li>
<li>
<a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a>
</li>
</ul>
</div>
</template>
<script>
export default {
name: "HelloWorld",
directives:{
'x':{
inserted(el){
el.addEventListener('click',()=>{console.log('x')})
},
},
},
props: {
msg: String
}
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
directiveOptions的属性
bind |
---|
bind(el,info,vnode,oldVnode)
类似于created
inserted |
---|
inserted(el,info,vnode,oldVnode)
类似于mounted
update |
---|
update(el,info,vnode,oldVnode)
类似于updated
componentUpdated |
---|
componentUpdated(el,info,vnode,oldVnode)
用的不多。
unbind |
---|
unbind(el,info,vnode,oldVnode)
类似于destroyed。
举例子 |
---|
自制v-on2指令,模拟v-on
先来个v-on
代码语言:javascript复制import Vue from "vue/dist/vue.js";
Vue.config.productionTip = false;
new Vue({
template: `
<button v-on:click="hi">点我</button>
`,
methods:{
hi(){
console.log('hi')
}
}
}).$mount("#app");

v-on2
代码语言:javascript复制import Vue from "vue/dist/vue.js";
Vue.config.productionTip = false;
new Vue({
directives:{
'on2':{
inserted(el,info){
el.addEventListener(info.arg,info.value)
},
unbind(el,info){
el.removeEventListener(info.arg,info.value)
}
}
},
template: `
<button v-on2:click="hi">点我</button>
`,
methods:{
hi(){
console.log('hi')
}
}
}).$mount("#app");

指令的作用
主要是拥有DOM操作 1.Vue实例/组件用于数据绑定、事件监听、DOM更新 2.Vue指令主要目的就是原生DOM操作
减少重复的DOM操作 1.如果某个DOM操作 你经常使用,那就可以封装成指令 2.如果某个DOM操作比较复杂,也可以封装为指令
混入 mixins
混入就是TMD复制 |
---|
前端就喜欢把简单概念搞复杂,就是做了一个复制的操作...叫的这么高大上。
如果说directives的作用 是减少DOM操作的重复,那么mixins的作用就是减少data,methods,钩子的重复。
场景描述 |
---|
假设,我们需要在每个组件上添加name和time,
在created、destroyed时,大厨提示,并报出存活时间
一共有五个组件,请问你怎么做? 一、给每个组件添加data和钩子,共五次 二、或者使用mixins减少重复
代码示例 |
---|
main.js
代码语言:javascript复制import Vue from "vue";
import App from "./App.vue"
Vue.config.productionTip = false;
new Vue({
render: h => h(App)
}).$mount("#app");
App.vue
代码语言:javascript复制<template>
<div id="app">
<Child1 />
<button>x</button>
<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",
components: {
Child1,
Child2,
Child3,
Child4,
Child5,
}
};
</script>
<style scoped>
#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.vue
代码语言:javascript复制<template>
<div>
Child1
</div>
</template>
Child2.vue
代码语言:javascript复制<template>
<div>
Child2
</div>
</template>
Child3.vue
代码语言:javascript复制<template>
<div>
Child3
</div>
</template>
Child4.vue
代码语言:javascript复制<template>
<div>
Child4
</div>
</template>
Child5.vue
代码语言:javascript复制<template>
<div>
Child5
</div>
</template>

需求:当Child1出生的时候,写一个Child1出生,点击×就关闭,并且打出Child1死亡了,以及生存时间
Child1.vue
代码语言:javascript复制<template>
<div>
Child1
</div>
</template>
<script>
export default {
data() {
return {
name: "Child1",
time: undefined
}
},
created() {
this.time = new Date()
console.log(`${this.name}出生了`)
},
beforeDestroy() {
const now = new Date()
console.log(`${this.name}死亡了,共生存了${now - this.time} ms`)
}
}
</script>
App.vue
代码语言:javascript复制<template>
<div id="app">
<Child1 v-if="Child1Visible"/>
<button @click="Child1Visible=false">x</button>
<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
}
},
components: {
Child1,
Child2,
Child3,
Child4,
Child5,
}
};
</script>
<style scoped>
#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-Child5都需要这个需求,怎么办?重复写5遍?
SB才这么做,就是这么直白~~~
首先,我们在src目录下创建一个mixins目录
然后在mixins目录中创建一个log.js文件,将刚才的内容写入
log.js
代码语言:javascript复制const log = {
data() {
return {
name: undefined,
time: undefined
}
},
created() {
if (!this.name){
throw new Error("need name")
}
this.time = new Date()
console.log(`${this.name}出生了`)
},
beforeDestroy() {
const now = new Date()
console.log(`${this.name}死亡了,共生存了${now - this.time} ms`)
}
}
export default log
其他的组件如何使用log?
Child1.vue
代码语言:javascript复制<template>
<div>
{{name}}
</div>
</template>
<script>
import log from '../mixins/log'
export default {
data() {
return {
name: "Child1"
}
},
mixins: [log]
}
</script>
Child2.vue
代码语言:javascript复制<template>
<div>
Child2
</div>
</template>
<script>
import log from '../mixins/log'
export default {
data() {
return {
name: "Child2"
}
},
mixins: [log]
}
</script>

继承extends
继承 |
---|
此继承非彼继承,这个继承和mixins有点像,都他妈的是复制,就是写法不太一样,所以我们来是想刚才的那个需求。
需求:当Child1出生的时候,写一个Child1出生,点击×就关闭,并且打出Child1死亡了,以及生存时间,然后我们不想每个组件中,都写一个mixins:[log],那么我们及来使用继承。
代码示例 |
---|
创建一个MyVue.js文件
代码语言:javascript复制import Vue from "vue"
const MyVue = Vue.extend({
data() {
return {
name: undefined,
time: undefined
}
},
created() {
if (!this.name) {
throw new Error("need name")
}
this.time = new Date()
console.log(`${this.name}出生了`)
},
beforeDestroy() {
const now = new Date()
console.log(`${this.name}死亡了,共生存了${now - this.time} ms`)
}
})
export default MyVue
Child1.vue
代码语言:javascript复制<template>
<div>
{{name}}
</div>
</template>
<script>
import MyVue from "../MyVue";
export default {
extends: MyVue,
data() {
return {
name: "Child1"
}
},
}
</script>

提供 provide 和 注入 inject
一键换肤 |
---|
举个例子,我们现在有一个需求,一键换肤的功能,默认是蓝色,可以切换为红色。 文字大小:默认正常,可以改成大或者小
祖先栽树(Provide) 后人乘凉(inject)
代码示例 |
---|
App.vue
代码语言:javascript复制<template>
<div :class="`app theme-${themeName}`">
<Child1/>
<button>x</button>
<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 {
themeName: "blue", // "red"
fontSize: "normal" // "big" |"small"
}
},
components: {
Child1,
Child2,
Child3,
Child4,
Child5,
}
};
</script>
<style scoped>
.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;
}
.app.theme-blue button {
background: blue;
color: white;
}
.app.theme-blue {
color: darkblue;
}
.app.theme-red button {
background: red;
color: white;
}
.app.theme-red {
color: darkred;
}
</style>
换肤按钮组件
在components中创建一个ChangeThemeButton.vue文件
代码语言:javascript复制<template>
<div>
<button>一键换肤</button>
</div>
</template>
引用到Child1中
Child1.vue
代码语言:javascript复制<template>
<div>
Child1
<ChangeThemeButton/>
</div>
</template>
<script>
import ChangeThemeButton from "./ChangeThemeButton"
export default {
components: {
ChangeThemeButton,
}
}
</script>
问题就出来了,就是我特么的,Child1.vue组件里面的按钮,点一下,怎么能把别人都换肤了呢?
这就触及到我的知识盲区了...
看标题... 是用provide和inject
provide提供给别人使用 |
---|
App.vue
代码语言:javascript复制<template>
<div :class="`app theme-${themeName}`">
<Child1/>
<button>x</button>
<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",
provide() {
return {
themeName: this.themeName,
changeTheme: this.changeTheme,
}
},
data() {
return {
themeName: "blue", // "red"
fontSize: "normal" // "big" |"small"
}
}
,
methods: {
changeTheme() {
if (this.themeName === 'blue') {
this.themeName = 'red'
} else {
this.themeName = 'blue'
}
}
},
components: {
Child1,
Child2,
Child3,
Child4,
Child5,
}
};
</script>
<style scoped>
.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;
}
.app.theme-blue button {
background: blue;
color: white;
}
.app.theme-blue {
color: darkblue;
}
.app.theme-red button {
background: red;
color: white;
}
.app.theme-red {
color: darkred;
}
</style>
ChangeThemeButton.vue
代码语言:javascript复制<template>
<div>
<button @click="z">当前主题色:{{themeName}}换肤</button>
</div>
</template>
<script>
export default {
inject: ['themeName','changeTheme'],
methods:{
z(){
this.changeTheme()
}
}
}
</script>


字体变化 |
---|
App.vue
代码语言:javascript复制<template>
<div :class="`app theme-${themeName} fontSize-${fontSizeName}`">
<Child1/>
<button>x</button>
<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",
provide() {
return {
themeName: this.themeName,
changeTheme: this.changeTheme,
changeFontSize: this.changeFontSize,
}
},
data() {
return {
themeName: "blue", // "red"
fontSizeName: "normal" // "big" |"small"
}
}
,
methods: {
changeTheme() {
if (this.themeName === 'blue') {
this.themeName = 'red'
} else {
this.themeName = 'blue'
}
},
changeFontSize(name) {
if (['normal', 'big', 'small'].indexOf(name) >= 0) {
this.fontSizeName = name
}
}
},
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;
}
.app.theme-blue button {
background: blue;
color: white;
}
.app.theme-blue {
color: darkblue;
}
.app.theme-red button {
background: red;
color: white;
}
.app.theme-red {
color: darkred;
}
.app.fontSize-normal {
font-size: 16px;
}
.app.fontSize-big {
font-size: 20px;
}
.app.fontSize-small {
font-size: 12px;
}
.app button {
font-size: inherit;
}
</style>
ChangeThemeButton.vue
代码语言:javascript复制<template>
<div>
<button @click="z">换肤</button>
<button @click="changeFontSize('big')">大字</button>
<button @click="changeFontSize('small')">小字</button>
<button @click="changeFontSize('normal')">正常字</button>
</div>
</template>
<script>
export default {
inject: ['themeName', 'changeTheme', 'changeFontSize'],
methods: {
z() {
this.changeTheme()
},
}
}
</script>
Child1.vue
代码语言:javascript复制<template>
<div>
Child1
<change-theme-button/>
</div>
</template>
<script>
import ChangeThemeButton from "./ChangeThemeButton.vue"
export default {
components: {
ChangeThemeButton,
}
}
</script>



provide 和 inject总结
代码语言:javascript复制作用:大范围的data和method等共用
注意:不能只传themeName不传changeTheme,因为themeName的值是被复制给provide的
// 传递引用也可以,但是不推荐,因为容易失控