Vue进阶构造属性

Rinsann 2021年09月24日 484次浏览

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>