Vue进阶属性:directives指令、mixins混入、extends继承、provide提供、inject注入

directives指令

自定义指令

一,声明一个全局指令

  1. Vue.directive('x',directiveOptions)

你就可以在任何组件里用v-x了

例子:元素在插入到页面时,就绑定click事件

  1. Vue.directive('x',{
  2. inserted:function(el){
  3. el.addEventListener('click',()=>{
  4. console.log('x')
  5. })
  6. }
  7. })

二,声明一个局部指令,只能在这个组件里使用

  1. export default{
  2. name:'hello',
  3. directives:{
  4. 'x':{
  5. inserted(el){
  6. el.addEventListener('click',()=>{})
  7. }
  8. }
  9. }
  10. }

directiveOptions

五个函数属性

  1. bind(el,info,vnode,oldVnode) -类似created
  1. inserted(el,info,vnode,oldVnode)-类似mounted
  1. update(el,info,vnode,oldVnode)-类似updated
  1. componentUpdated(el,info,vnode,oldVnode)- 用的不多
  1. unbind(el,info,vnode,oldVnode)- 类似destroyed

举例:

  1. new Vue({
  2. directives:{
  3. //声明on2指令
  4. on2:{
  5. inserted(el,info){
  6. console.log(info)
  7. //info.value是用户传来的值,这里会接到一个方法
  8. el.addEventListener(info.arg, info.value)
  9. },
  10. //元素销毁时
  11. unbind(el,info){
  12. //解绑事件
  13. el.removeEventListener(info.arg, info.value)
  14. }
  15. }
  16. },
  17. template:`
  18. <button v-on2:click="hi">点我</button>
  19. `,
  20. methods:{
  21. hi(){
  22. console.log('hi')
  23. }
  24. }
  25. })

如何缩写下面这部分?其实一般不缩写的!如何写请查文档!

  1. inserted(el,info){
  2. console.log(info)
  3. //info.value是用户传来的值,这里会接到一个方法
  4. el.addEventListener(info.arg, info.value)
  5. },
  6. //元素销毁时
  7. unbind(el,info){
  8. //解绑事件
  9. el.removeEventListener(info.arg, info.value)
  10. }

指令的作用

主要用于DOM操作
Vue实例/组件用于数据绑定、事件监听、DOM更新
Vue指令主要目的就是原生DOM操作
减少重复
如果某个DOM操作你经常使用,就可以封装为指令
如果某个DOM操作比较复杂,也可以封装为指令

mixins混入

混入其实就复制!!!

类比

directives的作用是减少DOM操作的重复
mixins的作用是减少data、methods、钩子的重复

场景

假设我们需要在每个组件上添加name和time
在created时,打出提示,并报出存活时间
一共有五个组件,请问你怎么做?
1 给每个组件添加dat和钩子,共五次
2 或者使用mixins减少重复

创建mixins文件夹和其下面的log.js文件

  1. const log = {
  2. //data里的属性会自动和下方Child1.vue的属性智能合并,undefined会被值:Child1覆盖掉
  3. data(){
  4. return{
  5. name:undefined,
  6. time:undefined
  7. }
  8. },
  9. created(){ //created也会智能合并
  10. //如果this.name不存在
  11. if(!this.name){
  12. throw new Error('需要name')
  13. }
  14. this.time = new Date()
  15. console.log(`${this.name}出生了`)
  16. },
  17. beforeDestroy(){
  18. const now = new Date()
  19. console.log(`${this.name}死亡了,共生存了${now - this.time}`)
  20. }
  21. }
  22. export default log

有Child1.vue,Child2.vue,Child3.vue,Child4.vue,Child5.vue
每个文件里,都导入log
这是Child1.vue:

  1. <script>
  2. import log from '../mixins/log.js'
  3. export default{
  4. data(){
  5. return {
  6. name:'Child1'
  7. }
  8. },
  9. mixins:[log] //等于把log及其内容复制到了这里
  10. }
  11. </script>

所以每个vue组件内都有了log的内容。

如果所有组件都要有log功能
可以在main.js中使用Vue.mixin

  1. Vue.mixin({
  2. data(){
  3. return{
  4. name:undefined,
  5. time:undefined
  6. }
  7. },
  8. created(){ //created也会智能合并
  9. //如果this.name不存在
  10. if(!this.name){
  11. throw new Error('需要name')
  12. }
  13. this.time = new Date()
  14. console.log(`${this.name}出生了`)
  15. },
  16. beforeDestroy(){
  17. const now = new Date()
  18. console.log(`${this.name}死亡了,共生存了${now - this.time}`)
  19. }
  20. })

全部组件就自动有了这些内容了。
这个方式不太好!

Extends 继承、扩展

减少重复

实现与mixins同样的需求

声明一个MyVue.js

  1. import Vue from 'vue'
  2. const MyVue = Vue.extend({ //关键词extend
  3. data(){
  4. return{
  5. name:undefined,
  6. time:undefined
  7. }
  8. },
  9. created(){ //created也会智能合并
  10. //如果this.name不存在
  11. if(!this.name){
  12. throw new Error('需要name')
  13. }
  14. this.time = new Date()
  15. console.log(`${this.name}出生了`)
  16. },
  17. beforeDestroy(){
  18. const now = new Date()
  19. console.log(`${this.name}死亡了,共生存了${now - this.time}`)
  20. }
  21. })

Child1.vue

  1. import MyVue from '../MyVue.js'
  2. export default{
  3. extends:MyVue, //关键词
  4. data(){}
  5. }

extends是比mixins更抽象一点的封装,用得少

Provide提供 和 Inject注入

换肤例子

App.vue

  1. <template>
  2. <div :class="`app theme-${themeName}`">
  3. <Child1 />
  4. </div>
  5. </template>
  6. <script>
  7. export default{
  8. name:"App",
  9. data(){
  10. return {
  11. themeName:"blue",
  12. fontSize:"normal"
  13. }
  14. }
  15. }
  16. </script>

components文件夹下的ChangeThemeButton.vue文件

  1. <template>
  2. <div>
  3. <button>换肤</button>
  4. </div>
  5. </template>

components文件夹下的Child1.vue文件,另外还有Child2.vue,Child3.vue,Child4.vue,Child5.vue

  1. <template>
  2. <div>Child1
  3. <change-theme-button /> //注意这里的大小写
  4. </div>
  5. </template>
  6. <script>
  7. import ChangeThemeButton from "./ChangeThemeButton.vue" //引入文件
  8. export default{
  9. components:{
  10. ChangeThemeButton //大小写
  11. }
  12. }
  13. </script>

问题来了,在ChangeThemeButton.vue里,如何改变App.vue的data来让皮肤变色???
答:用provide
App.vue:

  1. <template>
  2. <div :class="`app theme-${themeName}`">
  3. <Child1 />
  4. </div>
  5. </template>
  6. <script>
  7. export default{
  8. name:"App",
  9. //提供一个themeName的复制品出去
  10. provide(){
  11. return {
  12. themeName:this.themeName,//这里提供出去的只是一个新的值,所以那边改也无效,除非提供出去的是引用,但是不推荐,因为容易失控
  13. changeTheme:this.changeTheme
  14. }
  15. },
  16. data(){
  17. return {
  18. themeName:"blue",
  19. fontSize:"normal"
  20. }
  21. },
  22. methods:{
  23. changeTheme(){
  24. if(this.themeName === 'blue'){
  25. this.themeName = 'red'
  26. }else{
  27. this.themeName = 'blue'
  28. }
  29. }
  30. }
  31. }
  32. </script>

ChangeThemeButton.vue

  1. <template>
  2. <div>
  3. <button @click="x">换肤</button>
  4. </div>
  5. </template>
  6. <script>
  7. export default{
  8. inject:['themeName','changeTheme'], //注入上面代码提供的themeName
  9. methods:{
  10. x(){
  11. this.changeTheme()
  12. }
  13. }
  14. }
  15. </script>

可以换肤了。

总结

作用:共用大范围的data和method
注意:不能只传themeName不传changeTheme,因为themeName的值是被复制给provide的

资料来源:饥人谷