利用Vue自定义指令让你的开发变得更优雅
前段时间在用框架开发H5页面时,碰到框架中的组件内置了一个属性用于适配异形屏,虽然是组件内部实现的,但这个方式让我萌生一个想法:能不能自己写一个属性来实现这样的功能?
经过一番思索,我发现Vue的指令模式就很像属性的写法,在Vue中,我们利用模板指令诸如vifvfor等完成了许多工作,而Vue同样也支持自定义属性:constappVue。createApp({})注册一个全局自定义指令vfocusapp。directive(focus,{当被绑定的元素挂载到DOM中时mounted(el){聚焦元素el。focus()}})
然后你可以在模板中任何元素上使用新的vfocusattribute,如下inputvfocus
注:这里除了全局注册,也可以采用局部注册的方式,实际开发中可以使用vue另一项方便的功能mixin来将对应的指令混入你想使用的文件中,以达到代码的复用,那么开始进入正题吧。底部安全区适配
首先页面必须在head标签中添加meta标签,并设置viewportfitcover值directives:{safeAreaBottom:{bind(el,binding){constaddHighbinding。value0el。setAttribute(style,el。style。cssTextpaddingbottom:calc({addHigh}constant(safeareainsetbottom));paddingbottom:calc({addHigh}env(safeareainsetbottom)););}}}
使用:
如果设计图本身存在一个边距,则可以动态适配:
是不是很方便?我们再来看看另一个移动端H5会遇到的问题,并且还是用Vue指令来解决它。弹窗背景页不滚动
在移动端开发中,页面弹出滚动窗口时,需要将背景页固定住不动,否则会出现滚动穿透的现象。touchScroll:{inserted(){constscrollTopdocument。body。scrollTopdocument。documentElement。scrollTop;document。body。style。cssTextposition:fixed;width:100;top:scrollToppx;;},unbind(){constbodydocument。bodydocument。documentElement;body。style。position;consttopbody。style。top;document。body。scrollTopdocument。documentElement。scrollTopparseInt(top,10);body。style。top;}}是的,我是一个弹窗,当我出现时我的背景会吓得不敢动实现一个copy工具
有时我们需要页面点击可以一键复制的功能,可能大家都有用到一个叫vueclipboard的库,知道了指令的使用,实现一个copy自然也不在话下,那么就自己动手写一个vueCopy,为今后开发项目减少一个第三方库的使用吧。
首先我们看看这个工具是怎么使用的:
可以看出作者也是利用了指令,就照他这个思路,动手撸了一个,这里就直接上代码了,具体思路点见注释:clipboard:{bind(el,binding,{context}){constthiscontext利用arg用来注入回调函数if(binding。argsuccess){this。clipboardSuccessthis〔binding。expression〕}elseif(binding。argerror){this。clipboardErrorthis〔binding。expression〕}else{正常情况下就将文字缓存起来this。clipboardValuebinding。value}el。handler(){if(!this。clipboardValue){this。clipboardErrorthis。clipboardError(无内容)return}if(binding。arg){这里是因为属性被我们用了多次会多次执行,所以限制了执行次数return}try{consttextareadocument。createElement(textarea)textarea。readOnlyreadonly禁止输入,readonly防止手机端错误聚焦自动唤起键盘textarea。setAttribute(style,position:fixed;top:9999px;left:9999px;)它是可见的,但它又是不可见的textarea。valuebinding。valuedocument。body。appendChild(textarea)textarea。select()constresultdocument。execCommand(Copy)if(result){this。clipboardSuccessthis。clipboardSuccess(binding。value)这里可以定义成功回调返回的数据}document。body。removeChild(textarea)}catch(e){this。clipboardErrorthis。clipboardError(e)}}el。addEventListener(click,el。handler)},componentUpdated(el,{arg,value},{context}){更新值时候触发constthiscontextif(!arg){注册回调的部分不要赋值this。clipboardValuevalue}},unbind(el){el。removeEventListener(click,el。handler)},}
简单使用:点击直接复制到剪贴板
带回调的使用:templatecopycopyTexttemplate表单防止重复提交设置vthrottle自定义指令Vue。directive(throttle,{bind:(el,binding){letthrottleTimebinding。value;节流时间if(!throttleTime){用户若不设置节流时间,则默认2sthrottleTime2000;}letcbFun;el。addEventListener(click,event{if(!cbFun){第一次执行cbFunsetTimeout((){cbFunnull;},throttleTime);}else{eventevent。stopImmediatePropagation();}},true);},});
使用:buttonclicksayHellovthrottle提交button图片懒加载constLazyLoad{install方法install(Vue,options){代替图片的loading图letdefaultSrcoptions。default;Vue。directive(lazy,{bind(el,binding){LazyLoad。init(el,binding。value,defaultSrc);},inserted(el){兼容处理if(IntersectionObserverinwindow){LazyLoad。observe(el);}else{LazyLoad。listenerScroll(el);}},})},初始化init(el,val,def){datasrc储存真实srcel。setAttribute(datasrc,val);设置src为loading图el。setAttribute(src,def);},利用IntersectionObserver监听elobserve(el){letionewIntersectionObserver(entries{letrealSrcel。dataset。src;if(entries〔0〕。isIntersecting){if(realSrc){el。srcrealSrc;el。removeAttribute(datasrc);}}});io。observe(el);},监听scroll事件listenerScroll(el){lethandlerLazyLoad。throttle(LazyLoad。load,300);LazyLoad。load(el);window。addEventListener(scroll,(){handler(el);});},加载真实图片load(el){letwindowHeightdocument。documentElement。clientHeightletelTopel。getBoundingClientRect()。top;letelBtmel。getBoundingClientRect()。bottom;letrealSrcel。dataset。src;if(elTopwindowHeight0elBtm0){if(realSrc){el。srcrealSrc;el。removeAttribute(datasrc);}}},节流throttle(fn,delay){lettimer;letprevTime;returnfunction(。。。args){letcurrTimeDate。now();letcontextthis;if(!prevTime)prevTimecurrTime;clearTimeout(timer);if(currTimeprevTimedelay){prevTimecurrTime;fn。apply(context,args);clearTimeout(timer);return;}timersetTimeout(function(){prevTimeDate。now();timernull;fn。apply(context,args);},delay);}}}exportdefaultLazyLoad;
以上就是文章的全部内容,希望对你有所帮助!如果觉得文章写的不错,可以点赞收藏,也欢迎关注,我会持续更新更多前端有用的知识与实用技巧,我是茶无味de一天,希望与你共同成长