Vue3 learning (custom instruction directive)

directive-custom directives (belonging to destructive updates)


There are v-if, v-for, v-bind, v-show, v-model and a series of convenient and fast instructions in Vue. Let’s learn about the custom instructions provided in vue today.

1. Hook function of Vue3 instruction


When the created              element is initialized, the
beforeMount instruction is bound to the     element and called only once. The
mounted            element is inserted into the parent dom.
BeforeUpdate                is called before the element is    updated         . Called only once after removal



Vue2 指令 bind inserted update componentUpdated unbind

2. Define local instructions in setup


But there is a limitation to be aware of: local custom directives must be named in the form vNameOfDirective in order for them to be used directly in the template.

<template>
  <button @click="show = !show">开关{
   
   {show}} ----- {
   
   {title}}</button>
  <Dialog  v-move-directive="{background:'green',flag:show}"></Dialog>
</template>
const vMoveDirective: Directive = {
  created: () => {
    console.log("初始化====>");
  },
  beforeMount(...args: Array<any>) {
    // 在元素上做些操作
    console.log("初始化一次=======>");
  },
  mounted(el: any, dir: DirectiveBinding<Value>) {
    el.style.background = dir.value.background;
    console.log("初始化========>");
  },
  beforeUpdate() {
    console.log("更新之前");
  },
  updated() {
    console.log("更新结束");
  },
  beforeUnmount(...args: Array<any>) {
    console.log(args);
    console.log("======>卸载之前");
  },
  unmounted(...args: Array<any>) {
    console.log(args);
    console.log("======>卸载完成");
  },
};


3. Detailed explanation of life cycle hook parameters


The first el is currently bound to the DOM element

the second binding

instance : The component instance that uses the directive.
value : The value passed to the directive. For example, in v-my-directive="1 + 1" the value is 2.
oldValue : previous value, only available in beforeUpdate and updated. Available whether or not the value has changed.
arg : Arguments (if any) passed to the directive. For example, in v-my-directive:foo, arg is "foo".
modifiers : An object containing modifiers (if any). For example in v-my-directive.foo.bar the modifier object is {foo: true, bar: true}.
dir : An object, passed as an argument when registering the directive. For example, in the following directive

The virtual DOM of the third current element is Vnode

 

A virtual node on the fourth prevNode, only available in beforeUpdate and updated hooks 

4. Function shorthand


You may want to trigger the same behavior on mounted and updated, regardless of other hook functions. Then you can implement this function pattern by passing

<template>
   <div>
      <input v-model="value" type="text" />
      <A v-move="{ background: value }"></A>
   </div>
</template>
   
<script setup lang='ts'>
import A from './components/A.vue'
import { ref, Directive, DirectiveBinding } from 'vue'
let value = ref<string>('')
type Dir = {
   background: string
}
const vMove: Directive = (el, binding: DirectiveBinding<Dir>) => {
   el.style.background = binding.value.background
}
</script>


1. Case custom drag and drop command 

<template>
  <div v-move class="box">
    <div class="header"></div>
    <div>
      内容
    </div>
  </div>
</template>
 
<script setup lang='ts'>
import { Directive } from "vue";
const vMove: Directive = {
  mounted(el: HTMLElement) {
    let moveEl = el.firstElementChild as HTMLElement;
    const mouseDown = (e: MouseEvent) => {
      //鼠标点击物体那一刻相对于物体左侧边框的距离=点击时的位置相对于浏览器最左边的距离-物体左边框相对于浏览器最左边的距离
      console.log(e.clientX, e.clientY, "-----起始", el.offsetLeft);
      let X = e.clientX - el.offsetLeft;
      let Y = e.clientY - el.offsetTop;
      const move = (e: MouseEvent) => {
        el.style.left = e.clientX - X + "px";
        el.style.top = e.clientY - Y + "px";
        console.log(e.clientX, e.clientY, "---改变");
      };
      document.addEventListener("mousemove", move);
      document.addEventListener("mouseup", () => {
        document.removeEventListener("mousemove", move);
      });
    };
    moveEl.addEventListener("mousedown", mouseDown);
  },
};
</script>
 
<style lang='less'>
.box {
  position: fixed;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 200px;
  height: 200px;
  border: 1px solid #ccc;
  .header {
    height: 20px;
    background: black;
    cursor: move;
  }
}
</style>


2. Case permission button

<template>
   <div class="btns">
       <button v-has-show="'shop:create'">创建</button>
 
       <button v-has-show="'shop:edit'">编辑</button>
 
       <button v-has-show="'shop:delete'">删除</button>
   </div>
</template>
 
<script setup lang='ts'>
import { ref, reactive,  } from 'vue'
import type {Directive} from 'vue'
//permission
localStorage.setItem('userId','xiaoman-zs')
 
//mock后台返回的数据
const permission = [
    'xiaoman-zs:shop:edit',
    'xiaoman-zs:shop:create',
    'xiaoman-zs:shop:delete'
]
const userId = localStorage.getItem('userId') as string
const vHasShow:Directive<HTMLElement,string> = (el,bingding) => {
   if(!permission.includes(userId+':'+ bingding.value)){
       el.style.display = 'none'
   }
}
 
</script>
 
<style scoped lang='less'>
.btns{
    button{
        margin: 10px;
    }
}
</style>

Guess you like

Origin blog.csdn.net/liyp921210/article/details/129208222