Vue进阶构造属性

107 阅读2分钟

一、Directives 指令

  • v-开头,v-if、v-for、v-show等是内置属性

1、构造一个指令

  1. 声明一个全局指令
Vue.directive('x',{
  inserted:function(el){
    el.addEventListener('click',()=>{console.log('x')})
  }
})
  • 把v-x放在哪个元素上,el就表示哪个元素
  1. 声明一个局部指令
  • 想用在哪个实例,就在哪个实例选项中添加directives这项
new Vue({
  ...,
  directives:{
    x:{
      inserted(el){
        el.addEventListener('click',()=>{console.log('x')})
      }
    }
  }
})

2、directiveOptions属性

2.1、属性
  • bind:只调用一次,指令第一次绑定到元素时调用
  • inserted:被绑定元素插入父节点时调用(仅保证父节点存在)
  • unbind:只调用一次,指令与元素解绑时调用
  • 几乎不用的有两个,update、componentUpdated
2.2、参数
  • bind(el,info,vnode,oldVnode)
  1. el:绑定的元素
  2. info:除元素外其他的详细信息
  3. vnode:元素对应的虚拟节点
  4. oldVnode:之前的虚拟节点
  • directiveOptions属性都有这四个参数

3、自制v-on指令

  • <button v-on:click="hi">点我</button>,这个按钮被点击后,打印出“hi”,自制v-on2
new Vue({
  directives:{
    on2:{
      inserted(el,info){
        el.addEventListener(info.arg,info.value)  //info.arg获取到动作为click,info.value获取到函数为hi()
      },
      unbind(el,info){  //在该元素消亡时调用,要有这个好习惯,不然指令会越来越多
        el.removeEventListener(info.arg,info.value)
      },
    }
  }
  template:`
    <button v-on2:click="hi">点我</button>
  `,
  methods:{
    hi(){
      console.log('hi')
    }
  },
})

4、总结

  • 指令的主要目的就是原生DOM操作,数据绑定、事件监听、DOM更新等
  • 如果某个DOM操作经常使用(或比较复杂),就可以封装为指令

二、mixins 混入

  • 减少data、methods、钩子(即构造选项)的重复,可以理解为复制
  • 用代码理解mixins;需求:有5个组件,都要对其添加name和记录存活时长
  1. App.vue
<template>
  <div id="app">
    <Child1 v-if="child1Visible" />
    <button @click="child1Visible=false">消亡</button>
    ...
    <Child5 v-if="child5Visible" />
    <button @click="child5Visible=false">消亡</button>
  </div>
</template>
<script>
import Child1 from "./components/Child1.vue";
...
import Child5 from "./components/Child5.vue";
export default{
  name:"App",
  data(){
    return{
      child1Visible:ture,
      ...
      child5Visible:ture,
    }
  },
  components:{
    Child1,
    ...
    Child5,
  }
}
</script>
<style>
  ...
</style>
  1. 新建mixins目录,新建log.js文件(将共有的data、created、beforeDestroy放入)
const log={
  data(){
    return{
      name:undefined,
      time:undefined
    }
  },
  created(){
    if(this.name===undefined){
      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
  1. Child1.vue
<template>
  <div>Child1</div>
</template>
<script>
import log from '../mixins/log.js'
export default{
  data(){
    return{
      name:"Child1"  //mixins会做选项的智能合并,合并后this.name的值就为Child1
    }
  },
  mixins:[log]
}
</script>

三、extends 继承

  • 比mixins更抽象的封装,也可以理解为复制,只是形式不一样(推荐用mixins)
  • 延用上一个需求,换extends实现
  1. 新建MyVue.js文件
import Vue from "vue"
const MyVue=Vue.extend({  //内容和mixins:[log]一样
  data(){
    return{
      name:undefined,
      time:undefined
    }
  },
  created(){
    if(this.name===undefined){
      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
  1. Child1.vue
<script>
import MyVue from "../MyVue.js"
export default{
  extends:MyVue,
  data(){
    return{
      name:"Child1"  
    }
  }
}
</script>

四、provide 提供 inject 注入

  • provide:提供大范围共用的data和methods等
  • inject:隔代共享provide提供的信息
  • 用代码理解provide和inject;需求:一键换肤
  1. App.vue
<template>
  <div:class="`app theme-${themeName}`">  //相关样式写在style里
    <Child1 />
  </div>
</template>
<script>
import Child1 from "./components/Child1.vue";
export default{
  name:"App",
  provide(){  //提供这两个重要内容
    return{
      themeName:this.themeName,
      changeTheme:this.changeTheme
    }
  },
  data(){
    return{
      themeName:"blue"  //初始化是蓝色
    }
  },
  methods:{
    changeTheme(){  //变色方法
      if(this.themeName==='blue'){
        this.themeName='red'
      }else{
        this.themeName='blue'
      }
    }
  },
  components:{
    Child1
  }
}
</script>
<style>
  ...
</style>
  1. ChangeThemeButton.vue
<template>
  <div>
    <button @click="z">换肤</button>
  </div>
</template>
<script>
export default{
  inject:['themeName','changeTheme'],  //注入这两个重要内容
  methods:{
    z(){
      this.changeTheme()  //使用这个变色方法
    }
  }
}
</script>
  1. Child1.vue
<template>
  <div>Child1
    <change-theme-button />  //这样的写法Vue支持
  </div>
</template>
<script>
import ChangeThemeButton from "./ChangeThemeButton.vue";
export default{
  components:{
    ChangeThemeButton
  }
}
</script>