自定义指令
简介
除了默认内置的指令(列如 v-model
和 v-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>
函数简写
如果希望在 mounted
和 updated
时触发相同行为,而不关心其它的钩子函数。可以在第二个参数位置传入一个函数。
<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
,说明自定义指令已被忽略。