当前位置: 首页 > 科技观察

面试被问到Vue?想进一步改进吗?然后停下来看看

时间:2023-03-22 01:22:31 科技观察

.eqc-notifier{position:fixed;top:68px;left:50%;height:36px;padding-right:10px;line-height:36px;box-shadow:0016px0rgba(0,0,0,0.16);border-radius:3px;background:#fff;z-index:100;//最高层transform:translateX(-50%);animation:fade-in0.3s;.icon{margin:10px;font-size:16px;}.close{margin:8px;font-size:20px;color:#666;transition:all0.3s;cursor:pointer;&:hover{color:#ff296a;}}&.success{color:#1bc7b1;}&.fail{color:#ff296a;}&.info{color:#1593ff;}&.warn{color:#f89300;}&.close{animation:fade-out0.3s;}}Vue是最近最流行的前端框架。简单的入口方式和强大的API是它的优势。同时,由于其API的多样性和丰富性,其很多开发方式都不同于所有基于组件的React。如果你对Vue的API没有全面的了解(有些甚至在文档中都没有提及),那么在开发设计一个组件的时候,可能会绕一大圈,所以我强烈建议你先有一个学习Vue时了解所有Vue核心API。在这篇文章中,我将从实践出发,顺便总结一些知识点。文章很长,如果不能一下子看完,可以先收藏起来。如果你刚刚开始接触Vue,那么相信这篇文章一定会对你以后的提升有所帮助。言归正传,相信几乎任何一个项目都会有一个必不可少的功能,就是用户操作反馈或者提醒,就像这样(一个简单的demo)。其实在Vue的中大型项目中,这些类似的小功能会更加丰富和严谨,而在以Vue为核心框架的前端项目中,由于Vue本身是一个组件化的虚拟Dom框架,一个通知组件需要被实现的演示当然很简单。但是由于通知组件的使用特点,直接在模板中写组件,通过v-show或者props来控制通知组件的显示,显然是很不方便的,这意味着你的代码结构会发生变化。当层数很多的时候,我们把它们挂载在APP或者一个组件下显然是不合理的,如果要在action或者其他非组件场景下使用notifications,那么就无法实现纯组件模式的使用。那么有没有什么方法可以利用Vue的组件化特性方便的实现一个通知组件的显示,那么是否可以通过一个方法来控制弹出组件的显示和隐藏呢?目标1实现了一个简单的反馈通知,可以直接在组件中通过方法调用。例如,Vue.$confirm({...obj})首先,让我们实现通知组件。相信大部分人都能写出像样的组件。不啰嗦,直接放代码:.eqc-notifier{position:fixed;top:68px;left:50%;height:36px;padding-right:10px;line-height:36px;box-shadow:0016px0rgba(0,0,0,0.16);border-radius:3px;background:#fff;z-index:100;//最高层transform:translateX(-50%);animation:fade-in0.3s;.icon{margin:10px;font-size:16px;}.close{margin:8px;font-size:20px;color:#666;transition:all0.3s;cursor:pointer;&:hover{color:#ff296a;}}&.success{color:#1bc7b1;}&.fail{color:#ff296a;}&.info{color:#1593ff;}&.warn{color:#f89300;}&.close{animation:fade-out0.3s;}}这里需要注意的是,我们定义了一个close方法,但是内容是空的,虽然在template,但它似乎毫无意义。后面我们要扩展组件的时候,我会讲为什么要这样做。创建好这个组件后,我们就可以在模板中使用方法实现调用通知组件。在实现方法调用之前,我们需要对这个组件进行扩展,因为光有这些属性是不够我们使用的。在使用方法调用的时候,我们需要考虑几个问题:显示反馈的定位组件的出现和自动消失控制通知方法被连续调用多次,如何布局多个通知在这个前提下,我们需要对组件进行扩展,但是这些扩展的属性不能直接放在原来的组件中,因为这些可能会影响组件在模板中的使用,那怎么办呢?这时候,我们就要用到Vue中一个非常好用的API,extend,来继承原有组件的属性并进行扩展。看看代码通知程序)letvm=newUiNotifier({propsData:{type,msg},methods:{close:function(){letdialog=this.$eldialog.addEventListener('animationend',()=>{document.body.removeChild(dialog)这个.$destroy()})dialog.className=`${this.type}eqc-notifierclose`dialog=null}}}).$mount()document.body.appendChild(vm.$el)}functionsuccess(msg){open('成功',msg)}functionfail(msg){open('失败',msg)}functioninfo(msg){open('info',msg)}functionwarn(msg){open('警告',msg))}Vue.use(install)exportdefaultinstall可以看到这里实现了close方法,那为什么要在原来的组件中添加那些方法的定义呢?因为需要绑定在模板上,而模板不能扩展,只能覆盖。如果要覆盖重新实现,那么扩展意义不大。其实这只是一个消息弹窗组件,可以在模板中实现,具体如何注入插件,大家可以自行决定。同时在使用extend的时候要注意:方法和属性的定义是直接重写的。生命周期方法和yumixin类似,会合并,即原有组件和继承组件都会被调用。通过letUiNotifier=Vue.extend(Notifier)先调用原始组件,我们得到一个类似于Vue的子类,然后我们可以通过newUiNotifier({...options})创建一个Vue实例,创建的实例通过这个方法将会有组件定义里面的所有属性。创建实例后,vm.$mount()手动将组件挂载到DOM上,这样我们就可以不依赖Vue组件树输出DOM片段,达到自由显示通知的效果。扩展:(说说$mount,我们很多项目的主文件可能是这样的newVue({router,store,el:'#app',render:h=>h(App)})其实el和$mount的作用没有区别,都是将实例化的vue挂载到指定的dom元素上,如果在实例化vue的时候指定了el,则vue会渲染到这个el对应的dom中,否则,如果el是不指定,vue实例会处于“未挂载”状态,你可以通过$mount手动挂载。值得注意的是,如果$mount不提供参数,模板会渲染为文档,而你必须使用原生的DOMAPI才能插入到文档中,所以你应该明白我上面写的!这是$mount的源码片段,其实$mount方法支持传入2个参数,第一个是el,代表挂载的元素,可以是字符串,也可以是DOM对象,如果是字符串,会调用browse中的query方法r环境将其转换为DOM对象。第二个参数是和Server端渲染相关的,浏览器环境不需要传第二个参数。)嗯,其实我们现在可以在组件中调用this.notifier[state](msg),是不是是不是很方便?进阶我们刚刚在Vue中通过方法实现了用户反馈的提醒,又增加了一个难点:我们应该在我们的Vue项目中遇到过这种情况,弹出对话框或者选择框?不仅需要使用弹出的方法,还可以接收对话框交互返回的结果。这里就不详细分析了,直接上代码(之前的代码,用render写的组件,懒得改了,直接拿来用。。。),先创建一个dialog组件——--确认.vue。#__confirm{position:fixed;top:0;left:0;z-index:10;width:100%;height:100%;}#__confirm.bg{position:fixed;top:0;left:0;z-index:0;width:100%;height:100%;}#__confirm.box-container{position:absolute;width:500px;padding:20px;padding-top:30px;border-radius:3px;背景:#fff;z-index:1;box-shadow:2px2px10pxrgba(0,0,0,0.4);top:50%;left:50%;transform:translate(-50%,-50%);}#__confirm.content-box{font-size:14px;line-height:20px;margin-bottom:10px;}#__confirm.btn-box{margin-top:20px;text-align:right;}#__confirm.close-btn{position:absolute;top:15px;right:20px;font-size:16px;color:#666666;}#__confirm.close-btn:hover{color:#1593FF;}#__confirm.bg{position:fixed;}然后创建confirm.js:'使用strict'importConfirmfrom'./Confirm.vue'constconfirmConstructor=Vue.extend(Confirm)constConfirmViewStyle=config=>{constconfirmInstance=newconfirmConstructor({data(){return{config}}})confirmInstanceconfirmInstance.vm=confirmInstance.$mount()confirmInstanceconfirmInstance.dom=confirmInstance.vm.$eldocument.body.appendChild(confirmInstance.dom)}constclose=()=>{letdom=document.querySelector('body.modelServe-container')dom&&dom.remove()Vue.prototype。$receive=null}constcloseConfirm=()=>{letdom=document.getElementById('__confirm')dom&&dom.remove()Vue.prototype.$confirm=null}functioninstall(Vue){Vue.prototype.modelServe={confirm:(obj)=>{returnnewPromise(resolve=>{Vue.prototype.$confirm=(data)=>{resolve(data)closeConfirm()}ConfirmViewStyle(obj)})}}Vue.prototype.$dismiss=closeVue。原型ype.$cancel=closeConfirm}Vue.use(install)exportdefaultinstall有一个非常简单的想法。我们在创建的时候,同时返回一个promise,同时给vue暴露一个resolvepass的全局方法,就是把控件暴露在外面,这样我们就可以这样了,myconfirmam上面的.vue直接给$cancel绑定了cancel,给$confirm绑定了confirmation,所以点击确定进入full,也就是在.then中,当然你也可以传参this.modelServe.confirm({msg:'Thedata返回后不会保存,confirm?',ifBtn:true}).then(_=>{this.goBack()}).catch()有点过分,其实很多技术都可以扩展,比如作为在模态框中传入一个完整的组件并显示出来,简单的写一下,其实只需要稍微改一下就可以了。importModelfrom'./Model.vue'constmodelConstructor=Vue.extend(Model)constmodelViewStyle=(obj)=>{letcomponent=obj.componentconstmodelViewInstance=newmodelConstructor({data(){return{disabledClick:obj.stopClick//是否禁止点击覆盖覆盖关闭}}})letapp=document.getElementById('container')modelViewInstancemodelViewInstance.vm=modelViewInstance.$mount()modelViewInstancemodelViewInstance.dom=modelViewInstance.vm.$elapp.appendChild(modelViewInstance.dom)newVue({el:'#__model__',mixins:[component],data(){return{serveObj:obj.obj}}})}...Vue.prototype.modelServe={open:(obj)=>{returnnewPromise(resolve=>{modelViewStyle(obj,resolve)Vue.prototype.$receive=(data)=>{resolve(data)close()}})}}调用:sendCallBack(){this.modelServe.open({component:AddCallback,stopClick:true}).then(data=>if(data===1){this.addInit()}else{this.goBack()}})},这里使用了mixins,最后简单介绍一下mixins,扩展,延伸之间的差异。**-Vue.extend使用基础Vue构造函数创建一个“子类”。参数是一个包含组件选项的对象。mixins选项接受一组mixin对象。这些mixin实例可以像普通实例对象一样包含选项,它们最终将使用Vue.extend()中相同的选项合并逻辑进行合并。示例:如果你的mixin包含一个钩子,而构建组件本身也有一个,那么这两个函数都会被调用。Mixin钩子按照传入的顺序被调用,并且在组件自己的钩子被调用之前被调用。注意(数据混入组件数据优先级钩子函数会被混入一个数组,混入对象的钩子会在组件自身的钩子之前被调用,方法、组件、指令等值为对象的选项,将混入同一个对象。两个对象键名冲突时,取组件对象的键值对。)extends允许声明扩展另一个组件(可以是简单的选项对象或构造函数),而无需使用Vue.扩展。这主要是为了方便扩展单文件组件。这类似于mixins。**总结extend用于创建一个vue实例mixins可以混合成多个mixins,extends只能继承一个mixins类似于面向切面编程(AOP),extends类似于面向对象编程优先级Vue.extend>extends>mixins总结到这里,关于如何通过方法调用一个Vue组件内容以及使用的一些API和原理都差不多。不懂代码的可以随时提问。欢迎交流。