vue自定义指令分为
局部指令
全局指令
一.局部指令的开发
通过dirctives属性配置方式定义多个局部指令,通过key和value的定义来配置指令,局部指令只能在当前定义的vue实例对应的容器使用,如图:
如果多次调用就是多次执行指令
看个小案例,有一个盒子,需要使用指令进行拖拽,如何完成那,详情代码如下
<style>
body {
padding-bottom: 800px;
}
.box {
background-color: brown;
width: 100px;
height: 100px;
border-radius: 6px;
box-shadow: 0 0 6px #999;
cursor: pointer;
}
</style>
</head>
<body>
<div id="app">
<div class="box" v-drag></div>
</div>
<script type="module">
import { createApp } from "../assets/vue/3.0/vue.esm-browser.js";
createApp({
data() {
return {};
},
directives: {
// el 参数为自定义指令在页面调用时所对应的vnode生成的DOM元素
drag(el) {
el.style.position = "absolute";
// 绑定鼠标左键按下的事件
el.onmousedown = function (event) {
if (event.left != 0) return;
// 在按下的事件中再次绑定鼠标移动事件
let ox = event.offsetX;
let oy = event.offsetY;
console.log(ox, oy);
el.onmousemove = function (event) {
let px = event.pageX;
let py = event.pageY;
console.log(px, py);
el.style.top = py - oy + "px";
el.style.left = px - ox + "px";
};
};
// 绑定鼠标左键弹起的事件
el.onmouseup = function () {
// 在弹起时移除鼠标移动事件
el.onmousemove = null;
};
},
},
}).mount("#app");
</script>
二.全局指令开发
需要由应用程序对象的directive方法来完成自定义指令的描述
app.directive(指令命,指令的回调执行方法)
方法执行,跟局部指令可以比较差别,就可以看出区别,如图
注意:vue3的全局概念与vue2不同,vue3中的全局概念不在同一个环境就都属于vue语法的全局环境,vue3全局指的是由一个createApp作为全局启动代码,完成多个vue实例的加载,此时对于这些vue实例而言全局环境为创建APP
自定义指令的回调形参
自定义指令如何绑定data数据仓库的数据或者方法,在这里我们试用一下全局指令
指令定义是直接取值,回调方法相当于同时定义了初始化和变量更新调用两个功能
app.directive(指令命,指令的回调执行方法)根据全局指令中的binding来回调形参
modifieers
value
vue3中新增数据instance,表示的instance记录的是当前所在的容器对用的vue实例对象
注意如果程序运行中数据发生变化,oldValue也会发生变化
指令上一次=后的取值表达式运行的结果
dir记录的是当前指令被调用时定义的相关的生命周期钩子函数
图片预加载指令
使用全局指令来定义图片预加载
在开展前都必须去判断一下binding.value==binding.oldValue,如果相等即使没有变化,name就直接retuen.不在做处理
创造承载容器
data放图片数据
在vue实例没有被渲染出来时,图片是不能被渲染的,所以我们要在DOM 上有一个可显示的实例,所以使用循环将loading在一开始就加载出来
为了保证顾客的体验在图片没有加载完成前我们需要添加一个loading图片,然后再利用我们图片会被缓存的特性,只要发送请求的地址一致,就从缓存调用图片,完成图片的快速加载.
cssText在style包含了此标签上所有的文本属性
onload表示当前img加载完毕(onload使用在那个元素就表示那个元素的完成)
可以看到下图的样式如果写在全局指令里,就会影响他的样式,因为指令是可以多次调用,但是每个对图片的样式设置是不同的,为了避免这种情况出现,不要在指令里对样式进行处理,而是在行内直接对样式进行添加绑定
骨架屏
上述的loading是老版本使用,现在比较新的是骨架屏,利用CSS样式来完成,可以看一下代码,简单地写了一下样式,可以根据自己所需补充样式,让样式变得更完善
<style>
body {
padding-bottom: 800px;
}
img {
width: 400px;
height: 400px;
border: 1px solid #dedede;
}
/* 骨架屏 loading */
img[v-preload],
.preload {
background-color: #dedede;
background-image: linear-gradient(
to right,
rgba(255, 255, 255, 0) 0%,
rgba(255, 255, 255, 0.8) 10%,
rgba(255, 255, 255, 0) 20%
);
background-size: 230% 100%;
background-position: 30% 0%;
animation: skeleton 1.5s infinite;
}
@keyframes skeleton {
0% {
background-position: 30% 0%;
}
100% {
background-position: -100% 0%;
}
}
</style>
</head>
<body>
<div id="app">
<img v-preload=" img " style="object-fit: cover" />
</div>
<script type="module">
import { createApp } from "../assets/vue/3.0/vue.esm-browser.js";
const app = createApp({
data() {
return {
img: "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic.jj20.com%2Fup%2Fallimg%2F1112%2F11251Q24100%2F1Q125124100-5.jpg&refer=http%3A%2F%2Fpic.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1665718104&t=91a061cac8657bf9b1bc3ead30017584",
};
},
});
app.directive("preload", function (el, binding) {
if (binding.value == binding.oldValue) return;
el.classList.add("preload");
let imgDom = new Image();
imgDom.src = binding.value;
imgDom.onload = function () {
// console.log("图片加载完成");
el.src = binding.value;
el.classList.remove("preload");
};
});
app.mount("#app");
</script>