自定义指令
除了核心功能默认内置的指令 , Vue 也允许注册自定义指令。
功能: 对页面展示效果功能的扩展 ==> 自定义指令 主要完成的是 页面 DOM 元素
的操作
MVVM 设计模式核心思想:
简化开发者对于 DOM 的操作, vue 基本实现了
相关操作,基本上不需要完成 DOM 的操作
vue 简化开发者对于 DOM 的操作,实际上就是 将 DOM 的操作封装成插值表
达式或者指令
自定义指令是 vue 提供给开发者 对 DOM 操作的接口(规范化的方法)
1.局部指令定义
范围:仅限于定义时关联的 vue 实例的容器中使用
定义:
key ( string ):指令名称 ,定义完成后,页面使用需 v - 前缀调用指令
Vue . createApp ({
directives :{ key [ string ]: value [ Fuction ] }
}) 如果名称为驼峰命名方式 (例如 imgLazy ) , 页面使用时需要转换为 连
字符 ( v-img-lazy )
value ( Function ): function( el , binding , Vnode,preVnode ){} 指
令执行函数
el : 调用指令的当前 DOM 对象
binding : 是一个对象 ,对象中包含了指令构成 参数、修饰符、取值
……
name: 指令名称
rawName: 指令调用时的表达式
expression: 指令取值, = 右侧的取值表达式
arg: 指令参数 , : 后定义的参数名称
oldArg: 是指令 :
后定义的 旧的参数名称
value: 指令 = 右侧 表达式的计算结果
oldValue: 指令绑定变量发生变化后,调用该方法时 ,存储的 上次
的结果值
modifiers: 指令修饰符,
. 后定义的修饰符名称
modifiers 为 Object{ key:value } 类型数据
key 为修饰符名称, value 取值 为 true
true 作为 value 表示当前指令被启用
对象中没有修饰符 key , 表示指令不启用
当没有修饰符时,表示该对象为空对象
Vnode :指令更新后的新虚拟 DOM
preVnode :指令更新前的旧虚拟 DOM
使用: < 标签 v - 自定义指令名 [: 参数 ][. 修饰符 . 修饰符 ……][= 取值 ] ></ 标签 >
例:鼠标左键的拖拽
.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">
<p>app</p>
<div class="box" v-drag></div>
</div>
<!-- <hr> -->
<script type="module">
import { createApp } from "../assets/vue/3.0/vue.esm-browser.js";
const app = createApp({
data(){
return {
}
}
})
// vue3的全局概念不是在同一个环境就都属于vue语法的全局环境;
// vue3的全局指的是由一个createApp作为全局启动代码,完成多个vue实例的加载,此时对于这些vue实例而言全局环境为创建app
// 通过应用程序对象的 directive 方法完成一个自定义指令的描述
// app.directive(指令名,指令的回调执行方法)
app.directive("drag",function(el){
el.style.position="absolute";
el.onmousedown = function(event){
if(event.button!=0) return;
let ox = event.offsetX;
let oy = event.offsetY;
el.onmousemove = function(event){
let px = event.pageX;
let py = event.pageY;
el.style.top=(py-oy)+"px";
el.style.left=(px-ox)+"px";
}
}
el.onmouseup = function(){
el.onmousemove = null;
}
})
app.mount("#app")
</script>
2.全局指令定义
范围:可以在 vue 的 任意对象的容器中使用
语法: app.directive( id,definition )
id=name : 定义指令名称
definition : 指令的处理函数, function( el , binding ,
newVnode,oldVnode ){}
参数参考 局部指令
定义: 全局指令定义必须在使用之前 app . directive ( "lazy" , function ( el , binding , Vnode , preVnode ){
})
<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">
<p v-test>调用自定义指令test</p>
<p v-test>调用自定义指令test</p>
<p v-test>调用自定义指令test</p>
<br>
<div class="box" v-drag></div>
</div>
<!-- <div id="root">
<p v-test>调用自定义指令test</p>
</div> -->
<script type="module">
import { createApp } from "../assets/vue/3.0/vue.esm-browser.js";
createApp({
data(){
return {
}
},
// 通过属性配置方式定义多个局部指令
// 局部指令只能在当前定义的vue实例对应的容器中
directives:{
// key (String) 定义指令名称 => 在模板中可以通过 v-指令名称 方式进行调用
// value (Function) 定义指令的执行回调
test:function(){
console.log("自定义局部指令test");
},
// el 参数为自定义指令在页面调用时所对应的vnode生成的DOM元素
drag(el){
// console.log("自定义局部指令drag");
el.style.position="absolute";
// el.style.top="0px";
// el.style.left="0px";
// 绑定鼠标左键按下的事件
el.onmousedown = function(event){
// console.log("鼠标被点击:",event)
if(event.button!=0) return;
let ox = event.offsetX;
let oy = event.offsetY;
// 在按下的事件中再次绑定鼠标移动事件
el.onmousemove = function(event){
// console.log("移动:",event);
let px = event.pageX;
let py = event.pageY;
// console.log(px,ox);
// console.log(py,oy);
el.style.top=(py-oy)+"px";
el.style.left=(px-ox)+"px";
}
}
// 绑定鼠标左键弹起的事件
el.onmouseup = function(){
// 在弹起时移除鼠标移动事件
el.onmousemove = null;
}
}
}
}).mount("#app")
图片的预加载
方法一
<style>
body{
padding-bottom: 800px;
}
img{
width: 400px;
height: 400px;
border: 1px solid #dedede;
}
</style>
</head>
<body>
<div id="app">
<img v-preload=" img " style="object-fit:cover">
</div>
<script>
let arr = document.querySelectorAll("img[v-preload]");
arr.forEach((dom)=>{
dom.src = "../assets/img/loading.gif"
dom.tempStyle = dom.style.cssText;
dom.style.objectFit="scale-down";
dom.style.objectPosition="center";
})
</script>
<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.src = "../assets/img/loading.gif"
// let tempStyle = el.style.cssText;
// el.style.objectFit="scale-down";
// el.style.objectPosition="center";
let imgDom = new Image();
imgDom.src = binding.value;
imgDom.onload = function(){
// console.log("图片加载完成");
el.src = binding.value;
el.style.cssText = el.tempStyle;
}
})
app.mount("#app")
</script>
</body>
方法二
<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>