Vue进阶构造属性
directives、mixins、extends、provide、inject
Directives 指令
- 主要用于DOM操作,Vue实例/组件用于数据绑定、事件监听、DOM更新
- Vue指令主要目的就是原生的DOM操作,减少重复,某个DOM操作经常使用就可以封装成指令
// 声明全局指令
Vue.directive("x", /*directiveOptions*/{
inserted: function (el) {
el.addEventListener("click", () => {
console.log("x");
});
}
});
//局部指令
directives: {
x: {
inserted(el) {
el.addEventListener("click", () => {
console.log("x");
});
},
},
}
// directiveOptions有五个函数属性:bind/inserted/update/componentUpdate/unbind
Mixins 混入
- directives的作用是减少DOM操作的重复
- mixins的作用是减少data、methods、钩子的重复,选项会智能复制,Vue.mixin全局的不推荐使用
<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>
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;
<template>
<div>Child1</div>
</template>
<script>
import log from "../mixins/log.js";
export default {
data() {
return {
name: "Child1"
};
},
created() {
console.log("Child 1 的 created");
},
mixins: [log]
};
</script>
extends 继承
extends是比mixins更抽象的封装,如果mixins写太多次麻烦,可以考虑extends。
const MyVue = Vue.extend({
//mixins:[log]
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}`)
}
})
provide和inject 提供和注入
- 作用:大范围的data和method等共用
- 注意:不能只传themeName 不传 changeTheme,因为themeName的值是被复制给provide的
- 可以直接传引用,但是不推荐容易失控
<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,
fontSizeNmae: this.fontSizeName,
changeTheme: this.changeTheme, // 如果不生效,刷新一下 codesandbox
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(size) {
if (["normal", "big", "small"].indexOf(size) === -1) {
throw new Error(`wront size: ${size}`);
}
this.fontSizeName = size;
}
},
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 button {
font-size: inherit;
}
.app.fontSize-small {
font-size: 12px;
}
.app.fontSize-big {
font-size: 20px;
}
</style>
<template>
<div>Child 1
<change-theme-button/>
</div>
</template>
<script>
import ChangeThemeButton from "./ChangeThemeButton.vue";
export default {
components: {
ChangeThemeButton
}
};
</script>
<template>
<div>
<button @click="changeTheme">换肤</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"]
};
</script>