vue提供一个用户可以高度自定义的指令入口directives
利用这个入口我们实现一个常见的元素平滑移动的自定义指令 ‘sl
’
首先我们结合指令创建一个多元素的界面:
这个场景我们在很多网站,商城都有见过,特别对于移动端的清单类界面
我们的终极目标是在滚动的过程中出现在视口的元素移动,而并不是所有的元素都在移动
平滑移动
有了目标之后我们就可以分解一下我们codeing的过程,
- 创建一个基础的指令
- 选则一个何使的方式去建立一个高效的运动动画
- 如何获取到进入视口的元素
- 找到视口元素并让它移动
s1创建一个基础的指令文件
//移动的距离
const DISTANCE : number = 150;
const derDve = {
mounted(el:any){
el.style.transform=`translateY(${DISTANCE}px)`
}
}
export default derDve
s2指令内容根据分解的需求变更
- 指令使用的过程不应影响到原始元素的属性特征
el.style
方式会导致元素原有的样式出现变更 - 指令的使用应该具有兼容性和高效的复用价值
动画方式创建一个平滑指令
const derDve = {
mounted(el:any){
//动画方式创建
const animation = el.animate([
{
transform:`translateY(${DISTANCE}px)`,
opacity:0.5
},
{
transform:'translateY(0)',
opacity:1
}
],
{
duration:DURATION,
easing:'ease'
}
);
//初始状态下动画应该是停止状态
animation.pause();
},
}
export default derDve
s3一个好用的视口元素检测WebAPI IntersectionObserver
IntersectionObserver 一个浏览器自带的用于检测元素与视口是否有交集的api 接收两个参数,[callback,option] 详细配置可自行百度
有了这个api之后我们就可以对上述指令再次进行修改
//移动的距离
const DISTANCE : number = 150;
//动画时间
const DURATION : number = 1000;
//创建一个动画保存对象
const cations =new WeakMap(); //使用弱映射防止内存泄露
//创建一个视口元素监听
const ob= new IntersectionObserver(entries =>{
for(const entry of entries){
if(entry.isIntersecting){
const animation=cations.get(entry.target);
animation.play();
ob.unobserve(entry.target)
}
}
})
const derDve = {
mounted(el:any){
//动画方式创建
const animation = el.animate([
{
transform:`translateY(${DISTANCE}px)`,
opacity:0.5
},
{
transform:'translateY(0)',
opacity:1
}
],
{
duration:DURATION,
easing:'ease'
}
);
animation.pause();
cations.set(el,animation);
ob.observe(el);
},
unmounted(el:any){
ob.unobserve(el)
}
}
export default derDve
业务中使用也很简单
<li v-for="(item,index) in list" class="_cl_row" v-sl v-bg>{{item}}</li>
import derDve from "../../utils/silderAntiom";
import color from "../../utils/randomColor";
directives: {
sl: derDve, //平滑移动的指令
bg: color //随机颜色指令
},
setup(){
const list : Array<number> =[1,2,3,4,5,6,7,8,9,10,11,12]
}