vue组件的合并

可以把componentACopy组件合并到componentA组件

  1. let isInstall = false;
  2. const mixtureComponent = async (args1: Promise<typeof import('*.vue')>, args2: Promise<typeof import('*.vue')>) => {
  3. const c1 = await args1;
  4. const c2 = await args2;
  5. Object.defineProperties(c1.default, Object.getOwnPropertyDescriptors(c2.default));
  6. };
  7. const maxture = async () => {
  8. mixtureComponent(
  9. import('./componentA.vue'),
  10. import('./componentACopy.vue'),
  11. );
  12. };
  13. maxture();

使用import语法,要使用对象的default。如果使用require调用组件,不需要加default。

Vue2 创建插件

Vue.js 是一个易于使用的 Web 应用程序框架,我们可以使用它来开发交互式前端应用程序。
在本文中,我们将了解如何创建一个 Vue 插件来扩展我们应用程序的功能。
创建一个新的 Vue 插件很简单。我们只需要创建一个模块来导出一个包含install方法的对象。
install方法有一个VueVue 实例的参数,以及一个options对象,该对象接受我们通过调用Vue.use注册插件而传入的各种选项。
通过上述步骤,我们可以构建自己的插件。可以在函数中添加一个 mixin Vue.mixin
Mixins 让我们可以访问 Vue 生命周期钩子。
此外,我们可以添加属性来Vue.prototype为组件添加方法。
要创建一个简单的插件,我们可以编写以下代码:

  1. export default {
  2. install(Vue, options) {
  3. Vue.mixin({
  4. created() {
  5. console.log("hello");
  6. }
  7. });
  8. }
  9. };
  1. import Vue from "vue";
  2. import App from "./App.vue";
  3. import plugin from "./plugin";
  4. Vue.config.productionTip = false;
  5. Vue.use(plugin);
  6. new Vue({
  7. render: h => h(App)
  8. }).$mount("#app");

plugin.js中,我们使用默认导出一个对象install,其中包含方法,该方法具有 Vue 实例和options选项的参数,我们将其传递给 Vue 对象。
调用Vue.mixin全局created修改created钩子的方法,以便在初始化任何组件并created调用钩子时调用我们内部的任何内容。
由于我们console.log(‘hello’) mixin 内部,所以当我们的组件加载时会调用它。通过调用作为参数导入的全局注册了main.js我们的插件,[Vue.use(plugin)]
我们将‘hello’在控制台日志输出中看到记录。

传递options参数

要接受我们插件的选项,我们可以将它们传递给Vue.use我们的插件并使用它,如下所示:

  1. export default {
  2. install(Vue, options) {
  3. Vue.mixin({
  4. created() {
  5. const { greeting } = options;
  6. console.log(greeting);
  7. }
  8. });
  9. }
  10. };
  1. import Vue from "vue";
  2. import App from "./App.vue";
  3. import plugin from "./plugin";
  4. Vue.config.productionTip = false;
  5. Vue.use(plugin, { greeting: "hello jane" });
  6. new Vue({
  7. render: h => h(App)
  8. }).$mount("#app");

在上面的代码中,我们从参数中获取greeting属性。由于传入了一个带有greeting属性的对象作为的第二个参数Vue.use,我们将从‘hello jane’控制台日志输出中看到。

实例属性

我们可以通过向对象添加属性来将我们自己的实例属性添加到我们的插件中Vue.prototype
我们添加的属性应该以一个$符号开头,以将它们与我们在组件中定义的属性区分开来。
例如,我们可以添加自己的属性,如下所示:

  1. export default {
  2. install(Vue, options) {
  3. // 可以在mixin中调用vue的生命周期
  4. Vue.mixin({
  5. created() {
  6. const { greeting } = options;
  7. console.log(greeting);
  8. }
  9. });
  10. // 给原型上添加属性方法
  11. Vue.prototype.$bold = text => {
  12. return `<b>${text}</b>`;
  13. };
  14. }
  15. };
  1. <template>
  2. <div id="app" v-html="greeting"></div>
  3. </template>
  4. <script>
  5. export default {
  6. name: "App",
  7. data() {
  8. return {
  9. greeting: "hello"
  10. };
  11. },
  12. beforeMount() {
  13. this.greeting = this.$bold(this.greeting);
  14. }
  15. };
  16. </script>

在上面的代码中,我们在方法中有如下install方法:

  1. Vue.prototype.$bold = text => {
  2. return `<b>${text}</b>`;
  3. };

在我们的组件中调用,因为它是Vue原型的一部分。
那么在中App.vue,我们可以这样称呼它:

  1. this.greeting = this.$bold(this.greeting);

然后我们可以使用v-html如下指令设置文本App.vue

  1. <div id="app" v-html="greeting"></div>

全局过滤器

我们可以使用该Vue.filter方法添加一个全局过滤器。
filter方法接受一个带有过滤器名称的字符串作为第一个参数,而函数接受一个输入和值并返回我们喜欢的格式化值作为第二个参数。
例如,我们可以编写以下代码来做到这一点:

  1. export default {
  2. install(Vue, options) {
  3. Vue.filter("localeDateString", value => {
  4. if (!(value instanceof Date)) {
  5. return value;
  6. }
  7. return value.toLocaleDateString();
  8. });
  9. }
  10. };

在上面的代码中,我们有localeDateString过滤器,它返回从日期对象生成的日期字符串。
然后在中App.vue,我们可以这样使用它:

  1. <template>
  2. <div id="app">{{new Date() | localeDateString}}</div>
  3. </template>
  4. <script>
  5. export default {
  6. name: "App"
  7. };
  8. </script>

我们得到显示的依赖于语言环境的日期字符串,而不是默认的日期字符串。

自定义指令

可以调用该Vue.directive方法在我们的插件中添加指令。
该方法将指令名称字符串作为第一个参数,将指令对象作为第二个参数。

vue2中,自定义指令钩子函数

  • bind:只调用一次,指令第一次绑定到元素时调用。
  • inserted:被绑定元素插入父节点时调用
  • update:所在组件的 VNode 更新时调用
  • componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用
  • unbind:只调用一次,指令与元素解绑时调用

    钩子函数的4个参数

  • el:指令绑定的元素,可以操作DOM

  • binding:对象值,内部包括多个和指令相关的参数
    • name:指令名,不包括 v- 的名称
    • value:绑定的值,例如:v-my-directive=”1 + 1” 中,绑定值为 2
    • oldValue:指令绑定前一个值
    • expression:字符串形式的指令表达式,例如:v-my-directive=”1 + 1” 中,表达式为”1 + 1”
    • arg:传给指令的参数,可选;例如:v-focus:now, 参数为now
    • modifiers:包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }
  • vnode:生成的虚拟节点
  • oldVnode:上一个虚拟节点,仅在updatecomponentUpdated中使用

highlight自定义指令

  1. export default {
  2. install(Vue, options) {
  3. Vue.directive("highlight", {
  4. inserted(el) {
  5. el.style.color = "red";
  6. }
  7. });
  8. }
  9. };

在上面的代码中,添加了highlight指令,当我们将指令绑定到它时,它会将元素的内容更改为红色。
那么当我们使用它的时候如下:

  1. <template>
  2. <div id="app" v-highlight>foo</div>
  3. </template>
  4. <script>
  5. export default {
  6. name: "App"
  7. };
  8. </script>

最终得到‘foo’是红色的。

clickOutside指令

  1. export default {
  2. install(Vue, options) {
  3. Vue.directive("clickOutside", {
  4. bind(el, binding, vnode) {
  5. el.handler = (e)=>{
  6. if(!el.contains(e.target)){
  7. let method = binding.expression;
  8. vnode.context[method](); // 对应绑定的要触发的事件
  9. }
  10. }
  11. document.addEventListener("click", el.handler)
  12. },
  13. unbind(el){
  14. document.removeEventListener("click", el.handler)
  15. }
  16. });
  17. }
  18. };

使用,点击toggle可以显示出click按钮。点击灰色区域不会消失,只有点击外部才消失。

  1. <template>
  2. <div v-click-outside="loseEvent" style="display: inline-block;">
  3. <div style="background:#eee; width: 400px; height:100px;">
  4. <button @click="visible = true">toggle</button>
  5. <span v-show="visible"><button>click</button></span>
  6. <p>点击灰色区域,即被指令包括的区域,不会触发事件</p>
  7. </div>
  8. </div>
  9. </template>
  10. <script>
  11. export default {
  12. name: "App",
  13. components: {},
  14. data() {
  15. return {
  16. visible: false,
  17. };
  18. },
  19. methods: {
  20. loseEvent() {
  21. this.visible = false;
  22. },
  23. },
  24. };
  25. </script>

vue3创建指令

image.png

  1. const app = Vue.createApp({})
  2. // 注册一个全局自定义指令 `v-focus`
  3. app.directive('focus', {
  4. // 当被绑定的元素挂载到 DOM 中时……
  5. mounted(el) {
  6. // 聚焦元素
  7. el.focus()
  8. }
  9. })

通过Vue.createApp({})得到应用实例app,应用实例app身上有个directive(),用于创建一个全局的自定义指令,用的时候也非常简单 <input v-focus />

vue3自定义指令的钩子函数

  • created:在绑定元素的 attribute 或事件监听器被应用之前调用
  • beforeMount:当指令第一次绑定到元素并且在挂载父组件之前调用
  • mounted:在绑定元素的父组件被挂载后调用
  • beforeUpdate:在更新包含组件的 VNode 之前调用
  • updated:在包含组件的 VNode 及其子组件的 VNode 更新后调用
  • beforeUnmount:在卸载绑定元素的父组件之前调用
  • unmounted:卸载完成,只调用一次

    钩子函数中的4个参数

  • el:指令绑定到的元素。这可用于直接操作 DOM

  • binding:包含多个property属性的对象
    • instance:使用指令的组件实例
    • value:绑定的值,例如:v-my-directive=”1 + 1” 中,绑定值为 2
    • oldValue:指令绑定前一个值
    • arg:字符串形式的指令表达式,例如:v-my-directive=”1 + 1” 中,表达式为”1 + 1”
    • modifiers:包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }
    • dir:注册指令时作为参数传递
  • vnode:虚拟dom节点, 对应第一个参数el元素
  • preVnode:上一个虚拟节点,仅在 beforeUpdateupdated 钩子中可用

    自定义指令pin

    1. const pin = {
    2. mounted(el, binding) {
    3. //是否要定住
    4. var pinned = binding.value;
    5. //传入的修饰符,表示定在哪里
    6. var position = binding.modifiers;
    7. // 传递给指令的参数,可以表示定在的重要度
    8. var args = binding.arg;
    9. if (pinned) {
    10. el.style.position = 'fixed';
    11. if (args == "warning") {
    12. el.style.backgroundColor = "pink";
    13. }
    14. for (var val in position) {
    15. if (position[val]) {
    16. el.style[val] = '10px';
    17. }
    18. }
    19. } else {
    20. el.style.position = 'static';
    21. el.style.backgroundColor = "";
    22. }
    23. }
    24. }
    25. export default pin
    示例链接

结论

通过创建一个导出和对象的模块来创建自己的 Vue 插件install
该方法接受一个Vue 实例的参数和一个参数options传入的选项的对象。
使用方法Vue.use(plugin)
在插件内部可以定义 Vue 指令、mixins 和过滤器。