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

Vue.js的注意事项

时间:2023-03-14 01:10:10 科技观察

Vue.js是一个很棒的框架。然而,当你开始构建一个大型JavaScript项目时,你会对Vue.js感到有点困惑。这些困惑并非来自框架本身,相反,Vue.js团队会经常调整一些重要的设计策略。Vue.js针对的是几个不同级别的开发人员,而不是React和Angular。它更友好,无论是对于初学者还是经验丰富的老手。它没有隐藏一些DOM操作,相反它与DOM配合得很好。这篇文章更像是一个目录,列出了我在Vue.js初学者路上遇到的一些问题和技巧。了解这些关键设计技术有助于我们构建大型Web应用程序。截至撰写本文时,即2018年5月18日,以下提示仍然有效。但是当框架升级时,或者当底层浏览器或JSAPI发生变化时,它们可能会变得不那么有用。译者注:虽然Vue.js3即将到来,但是下面的大部分技术都是有用的,因为3版本不会改变一些上层的API。最大的特点可能是底层数据Observer改为代理实现,并且源码使用typescript构建。1、为什么Vue.js不用ESClasses来写组件?如果你用过类似于Angular或者一些后端OOP语言的框架,那么你的第一个问题可能是:为什么不用Class组件?Vue.js的作者在GitHubissues中很好的回答了这个问题:UsestandardJSclassesinstead自定义语法?为什么不使用Class这里有三个很重要的原因:ESClasses不能满足当前Vue.js的需求,ESClasses标准还没有完全标准化,一直在朝着错误的方向发展。如果类的私有属性和装饰器(目前处于第3阶段)稳定下来,这可能会有所帮助。ESClasses只适合熟悉面向对象语言的人,对不使用复杂构建工具和编译器的人不友好。一个优秀的UI组件层次结构一般是组件水平组合,而不是基于继承的层次结构。Classes形式显然更擅长后者。译者注:但是,Vue.js3.0将支持基于Class的组件编写,真香。2.如何构建自己的抽象组件?如果你想构建自己的抽象组件(比如transition、keep-alive),这是一个比构建大型Web应用程序更疯狂的想法。有一些关于这个问题的讨论,但不是什么都没有发生。有抽象组件文档的计划吗?译者注:在Vue.js内部组件(transition,keep-alive)中,使用了一个抽象属性来声明抽象组件。此属性的作者不打算向所有人开放。所以文档也没有提到这一点。但是如果你想用也是可以的,那就得深入源码去探究这个属性是干什么的了。但不要担心,如果你能很好地理解插槽,你就可以构建自己的抽象组件。这是一篇关于如何执行此操作的好博客文章。WritingAbstractComponentswithVue.js译者注:以下是对《在 Vue.js 中构建抽象组件》的简单翻译抽象组件和普通组件一样,只是它在界面上不显示任何DOM元素。它们只是向现有组件添加额外的行为。就像你已经熟悉的Vue.js的许多内置组件,例如:``、``、``。现在展示一个如何跟踪DOM进入视口的案例,让我们使用IntersectionObserverAPI来实现一个抽象组件来解决这个问题。(完整代码在这里:[vue-intersect](https://github.com/heavyy/vue-intersect))//IntersectionObserver.vueexportdefault{//EnableabstractcomponentsinVue//该属性官方没有document,随时可能改变,但是我们的组件必须使用它abstract:true,//重新实现一个渲染函数render(){//我们不需要任何包装元素,只返回子组件try{returnthis.$slots.default[0];}catch(e){thrownewError('IntersectionObserver.vuecanonlyrenderone,andexactlyonechildcomponent.');}returnnull;},mounted(){//创建IntersectionObserver实例this.observer=newIntersectionObserver((entries)=>{this.$emit(entries[0].isIntersecting?'intersect-enter':'intersect-leave',[entries[0]]);});//需要等待下一个事件队列,以确保子元素已经被渲染了this.$nextTick(()=>{this.observer.observe(this.$slots.default[0].elm);});},destroyed(){//确保当组件被移除,IntersectionObserver实例也将Stopl正在听this.observer.disconnect();}}让我们看看如何使用它?但在这样做之前,请三思,我们一般都是靠mixins和一些纯函数来解决一些特殊场景的问题。你可以直接把mixins看成一个抽象的组件。如何在单文件组件中扩展另一个VueJS组件?(ES6vue-loader)3.我不是很喜欢Vue.js的单文件组件。我更喜欢将HTML、CSS和JavaScript分开。没有人会阻止你这样做,如果你是一个分离哲学家,喜欢将不同的东西放在单独的文件中,或者讨厌编辑器对.vue文件的不稳定行为,那么这样做是可以的。你要做的很简单:这样做,就下一个问题会出现:我的组件会不会一直需要4个文件(vue+html+css+js)?我可以摆脱.vue文件吗?答案是肯定的,可以使用vue-template-loader。我的同事还为此写了一篇很棒的教程:Usingvue-template-loaderwithVue.jstoCompileHTMLTemplates4.函数式组件感谢React.js函数式组件很受欢迎,因为它们是无状态的,易于测试。但是,它们也存在一些问题。译者注:如果对Vue.js函数式组件不了解,可以先去官方文档查看:官方文档4.1函数式组件为什么不能使用基于Class的@Component装饰器?再次回到Classes,它只是一种为本地状态保存数据结构的方法。如果功能组件是无状态的,那么使用@Component装饰器是没有意义的。这里有一个讨论:Howtocreatefunctionalcomponentin@Component?4.2外部类和样式不应应用于功能组件功能组件不能像普通组件那样绑定特定的类和样式,必须在render函数中手动应用这些绑定。DOM类属性未正确呈现,功能组件在功能组件上忽略了类属性4.3功能组件总是重新呈现?TLDR:在功能组件中使用有状态组件时要小心。当props不变时,功能组件会重新渲染。函数式组件相当于直接调用组件的Render函数,这意味着你应该:避免在render函数中直接使用有状态组件,因为这样会在每次调用render函数时创建不同的组件实例。如果功能组件是叶子组件,则可以更好地利用它们。请注意,同样的行为也适用于React.js。4.4如何在Vue.js功能组件中触发事件?从功能组件触发事件并不容易。不幸的是,文档中也没有提到这一点。$emit方法在功能组件中不可用。stackoverflow上有人讨论了这个问题:HowtoemitaneventfromVue.jsFunctionalcomponent?5.Vue.js的透明包装器组件包装了一些DOM元素,并暴露了这些DOM元素的事件,而不是根DOMNode实例。例如:这里真正让我们感兴趣的是输入节点,而不是div根节点,因为它主要是为了样式和装饰添加的。用户可能对该组件的几个输入事件感兴趣,例如模糊、聚焦、点击、悬停等。这意味着我们必须重新绑定每个事件。我们的组件看起来像这样。其实这是完全没有必要的。简单的解决方案是使用Vue实例上的属性vm.$listeners将事件重新绑定到所需的DOM元素:6.为什么不能在slot上绑定和触发事件?经常看到一些开发者在slot上监控分发事件,这是不可能的。组件的槽由调用它的父组件提供,这意味着所有事件都应该与父组件相关联。尝试监听这些变化意味着您的父组件和子组件是紧密耦合的,但是还有另一种方法可以做到这一点,EvanYou对此做了很好的解释:Isitpossibletoemiteventfromcomponentinsideslot#4332Suggestion:v-On在slots7上,slotinslot(访问grandchildrenslot)在某些时候可能会遇到这种情况。假设有一个组件,比如A,它接受一些插槽。遵循组合原则,使用组件A构建另一个组件B。然后你在C中使用B。那么问题来了:如何将C组件的slot传递给A组件呢?要回答这个问题,首先要看你是怎么构建组件的。如果使用render函数,就很简单了。你只需要在组件B的渲染函数中执行以下操作://RenderfunctionforcomponentBfunctionrender(h){returnh('component-a',{//PassingslotsastheyaretocomponentAscopedSlot:this.$scopedSlots}}但是,如果你使用基于模板的way,那就有点不好了。幸运的是,在这个问题上已经有了进展:feat(core):supportpassingdownscopedSlotswithv-bind希望这篇文章能让你对Vue.js的设计有更深入的理解,给你一些高级场景的提示。