6 Vue2 进阶构造属性

105 阅读2分钟

自定义指令官方文档 Vue.directive( id, [definition] )

自定义简单的指令v-onall,全局自定义

定义无参数的指令v-onall代码如下,注意,v-在定义时是省略的,Vue.directive第二个参数中传入有回调函数inserted,0表示元素插入到页面中时进行回调;

Vue.directive('onall', {
  inserted: function (el) {
    el.addEventListener('click', () => {
      console.log("全局指令监听到点击事件!")
    });
  }
});

除了inserted回调函数,还有其他回调函数
使用v-onall指令:

<button v-onall>全局</button>

点击按钮【全局】,触发了按键监听事件;

自定义简单的指令v-onpart,局部定义

new Vue({
  directives: {
    part: {
      inserted: function (el) {
        el.addEventListener('mousedown', () => {
          console.log("局部指令监听到事件!");
        })
      }
    }
  },
  template: `
    <div>
    <button v-onpart>局部</button>
    </div>
  `,
}).$mount("#app");

模拟v-on2:click指令

定义是这样的,其中inof是指令后面的参数

directives: {
  myon: {
    inserted: function (el,info){
      el.addEventListener(info.arg,info.value);
    },
    unbind: function (el,info){
      el.removeEventListener(info.arg, info.value);
    }
  }
},

使用是这样的,其中mylog是一个函数

<button v-myon:click = "mylog">v-myon</button>

指令的作用

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

mixins,封装组件的公共部分,可以理解为智能复制

假设有3个组件,Child1,Child2,Child3,他们都有共同的data和钩子操作:
组件Child1如下:

<template>
<span>Child-1</span>
</template>
<script>
export default {
  name: "Child1",
  data(){
    return {
      name: "Child1",
      time: undefined,
    }
  },
  created() {
    this.time = new Date();
    console.log(`${this.name} created!`);
  },
  beforeDestroy() {
    const stay = (new Date()) - this.time;
    console.log(`${this.name} destroyed, stay ${stay}s`)
  }

}
</script>
<style scoped>
</style>

类似的还有Child2Child3,这三个组件中的data和钩子函数如created/beforDestroy都相同的部分你,怎么复用呢,拷贝出来!
mixins复用方法:

  1. 把公共部分抽出来,以对象的形式,放在一个js文件中,再暴露出来,
const log  = {
    data(){
        return {
            name: "Child1",
            time: undefined,
        }
    },
    created() {
        this.time = new Date();
        console.log(`${this.name} created!`);
    },
    beforeDestroy() {
        const stay = (new Date()) - this.time;
        console.log(`${this.name} destroyed, stay ${stay}s`)
    }
}
export default log;

2.在控件中导入mxins文件,并自定义特有字段,比如下面例子中,timecreated用的是mixins提供的公共数据,namebeforDestroy都是控件中特有的,会覆盖掉mixins提供的数据,这就是智能合并

<script>
import log from "@/mixins/log";
export default {
  name: "Child3",
  data(){
    return {
      name: "Child3",
    }
  },
  mixins:[log],
  beforeDestroy() {
    const wait = (new Date()) - this.time;
    console.log(`最后一个出生的${this.name}死亡了,时间是${wait}`)
  }
}
</script>

Extends继承、扩展,其实也是一种智能复制

  1. 创建Vue的扩展,里面包含了其他Vue组件用的公共数据,具体做法是创建一个MyVue.js文件,然后暴露出来,要特别注意,用的是Vue.extend(),没有s
import Vue from "vue/dist/vue";
const MyVue = Vue.extend({
    data(){
        return {
            name: "Child1",
            time: undefined,
        }
    },
    created() {
        this.time = new Date();
        console.log(`${this.name} created!`);
    },
    beforeDestroy() {
        const stay = (new Date()) - this.time;
        console.log(`${this.name} destroyed, stay ${stay}s`)
    }
});
export default MyVue;
  1. 在组件中Extends组件
<script>
import MyVue from "@/MyVue";
export default {
  name: "Child4",
  data(){
    return {
      name: "Child4",
    }
  },
  extends: MyVue,
}
</script>

provide和inject

父控件AppTheme中,定义全局的皮肤样式,保存在全局的data中,在AppTheme下的子控件Child1中,有一个换肤控件ChangeThemeButton,这个子控件如何修改全局的皮肤样式?

  1. 在父组件中用provide()函数,通过一个对象把数据暴露出来
provide() {
  return {
    "themeName": this.themeName,
    "themeNameFun": () => {
      return this.themeName;
    },
    "changeThemeName": this.changeThemeName,
  }
},

其中,"themeName"暴露的是数据,而且是基础类数据,但是这种暴露是一次性的,父组件改了,子组件不能响应式更新,"themeNameFun"暴露的是一个函数,返回基础类型数据,这种暴露是响应式的,子组件能够响应式更新,"changeThemeName"暴露的是一个函数,子组件可以调用; 2. 在子组件或者其他组件中用inject:["name"]对象注入父组件暴露的数据

<script>
export default {
  name: "ChangeThemeButton",
  inject: ["themeNameFun", "changeThemeName"],
  methods: {
    change() {
      this.changeThemeName(this.themeNameFun() === "red" ? "blue" : "red")
    }
  }
}
</script>

在子组件中,themeNameFun是从外部注入的,但是注入后使用,就和在methods中定义的方法一样; 3. 父组件可以通过provide(){return{"name":object}}把对象暴露出来,其他组件响应式更新,但这样做并不值得提倡。