自定义指令
除了核心功能默认内置的指令 ,
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>