可复用 & 组合--③:自定义指令

自定义指令

简介

除了默认内置的指令(列如 v-modelv-show),Vue 也允许注册自定义指令。

比如:页面加载时,input 元素获得焦点。

通过注册全局指令实现

<body>
  <div id="app">
    <input type="text" v-focus />
  </div>

  <script src="https://unpkg.com/vue@next"></script>
  <script>
    const { createApp, directive } = Vue;
    const Root = {};
    const app = createApp(Root);

    // 注册全局指令
    app.directive("focus", {
      mounted(el) {
        // 当被绑定的元素挂载到 DOM 中时执行
        // el 代表被绑定指令的元素
        el.focus();
      },
    });

    app.mount("#app");
  </script>
</body>

通过注册局部指令实现

<body>
  <div id="app">
    <!-- v-focus 是局部指令,只能在 my-component 组件中使用,否则报错 -->
    <!-- <input type="text" v-focus /> -->
    <my-component></my-component>
  </div>

  <script src="https://unpkg.com/vue@next"></script>
  <script>
    const { createApp, directive } = Vue;
    const Root = {};
    const app = createApp(Root);

    app.component("my-component", {
      template: `<div><input type="text" v-focus /></div>`,
      directives: {
        focus: {
          mounted(el) {
            el.focus();
          },
        },
      },
    });

    app.mount("#app");
  </script>
</body>

钩子函数

钩子函数执行时机
created在绑定元素的 attribute 或事件监听器被应用之前调用(不懂)
beforeMount被绑定指令的元素挂载到 DOM 之前调用
mounted被绑定指令的元素挂载到 DOM 之后调用
beforeUpdate被绑定指令的元素所在的组件更新之前调用
updated被绑定指令的元素所在的组件更新之后调用
beforeUnmount被绑定指令的元素所在的组件卸载之前调用
unmounted被绑定指令的元素所在的组件卸载之后调用
<body>
  <div id="app">
    <my-component v-if="isShow"></my-component>
    <button @click="rootClick">切换</button>
  </div>

  <script src="https://unpkg.com/vue@next"></script>
  <script>
    const { createApp, directive, ref } = Vue;
    const Root = {
      setup() {
        const isShow = ref(true);
        const rootClick = function () {
          isShow.value = !isShow.value
        }

        return {
          isShow,  
          rootClick
        };
      },
    };
    const app = createApp(Root);

    app.directive("test", {
      created() {
        console.log("created...");
      },
      beforeMount() {
        console.log("beforeMount...");
      },
      mounted() {
        console.log("mounted...");
      },
      beforeUpdate() {
        console.log("beforeUpdate...");
      },
      updated() {
        console.log("updated...");
      },
      beforeUnmount() {
        console.log("beforeUnmount...");
      },
      unmounted() {
        console.log("unmounted");
      },
    });

    app.component("my-component", {
      name: "my-component",
      template: `
        <div v-test>
          <p>my-component</p>
          <div>
            {{ count }}<button @click="myClick">Add</button>
          </div>
        </div>
      `,
      setup() {
        const count = ref("100");

        const myClick = function () {
          count.value++;
        };

        return {
          count,
          myClick,
        };
      },
    });

    app.mount("#app");
  </script>
</body>

动态指令参数

指令的参数和绑定值可以是动态的。

<body>
  <div id="app">
    <div
      style="width: 50px; height: 50px; background: pink"
      v-padding:[direction]="distance"
    ></div>
    <div>
      <button @click="rootClick">{{ direction }}</button>
    </div>
    <div>
      <input type="range" min="0" max="50" v-model="distance" />{{ distance }}
    </div>
  </div>

  <script src="https://unpkg.com/vue@next"></script>
  <script>
    const { createApp, directive, ref } = Vue;
    const Root = {
      setup() {
        const direction = ref("开始");
        const distance = ref("0");
        const arr = [
          "border-top",
          "border-right",
          "border-bottom",
          "border-left",
        ];
        let index = 0;

        const rootClick = function () {
          index > 3 ? (index = 0) : "";
          direction.value = arr[index++];
        };

        return {
          direction,
          distance,
          rootClick,
        };
      },
    };
    const app = createApp(Root);

    app.directive("padding", {
      updated(el, binding) {
        el.style.border = "unset";
        el.style[binding.arg] = binding.value + "px" + " solid orange";
      },
    });

    app.mount("#app");
  </script>
</body>

函数简写

如果希望在 mountedupdated 时触发相同行为,而不关心其它的钩子函数。可以在第二个参数位置传入一个函数。

<body>
  <div id="app">
    <input type="text" v-focus />
    {{counter }}
    <button @click="myClick">更新</button>
  </div>

  <script src="https://unpkg.com/vue@next"></script>
  <script>
    const { createApp, directive, ref } = Vue;
    const Root = {
      setup() {
        const counter = ref('0')
        const myClick = function () {
          counter.value++
        }

        return {
          counter,
          myClick
        }
      },
    };
    const app = createApp(Root);

    app.directive("focus", (el, binding) => {
      console.log("执行了...");
    });

    app.mount("#app");
  </script>
</body>

对象字面量

如果指令需要多个值,可以传入一个 JS 对象字面量。

<body>
  <div id="app">
    <input type="text" v-user="{ name: 'cezlz', age: 18 }" />
  </div>

  <script src="https://unpkg.com/vue@next"></script>
  <script>
    const { createApp, directive, ref } = Vue;
    const Root = {};
    const app = createApp(Root);

    app.directive("user", (el, binding) => {
      console.log(binding.value);
    });

    app.mount("#app");
  </script>
</body>


在组件中使用

在组件中使用时,自定义指令总是会被应用在组件的根节点上。

<body>
  <div id="app">
    <my-component v-test></my-component>
  </div>

  <script src="https://unpkg.com/vue@next"></script>
  <script>
    const { createApp, directive } = Vue;
    const Root = {};
    const app = createApp(Root);

    app.directive("test", (el, binding) => {
      console.log(el.id)
    });

    app.component("my-component", {
      name: "my-component",
      template: `
        <div id="box1">
          <div id="box2">my-component</div>
        </div>
      `,
    });

    app.mount("#app");
  </script>
</body>

结果是打印出box1 ,说明自定义指令应用在根节点。


如果组件有多个根节点,则自定义指令会被忽略,并且抛出一个警告。

<body>
  <div id="app">
    <my-component v-test></my-component>
  </div>

  <script src="https://unpkg.com/vue@next"></script>
  <script>
    const { createApp, directive } = Vue;
    const Root = {};
    const app = createApp(Root);

    app.directive("test", (el, binding) => {
      console.log(el.id)
    });

    app.component("my-component", {
      name: "my-component",
      template: `
        <div id="box1">my-component</div>
        <div id="box2">my-component</div>
      `,
    });

    app.mount("#app");
  </script>
</body>

现在并不会打印出 box1,说明自定义指令已被忽略。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值