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

在Vue.js中使用Mixin

时间:2023-03-19 00:45:10 科技观察

有一个很常见的情况:有两个非常相似的组件,它们的基本功能是一样的,但是它们之间有足够多的差异,这时候你可以似乎得出一个岔路口:我应该把它分成两个不同的部分吗?还是保留为一个组件,然后通过props传值,制造差异来区分?两种解决方案都不够***:如果拆分成两个组件,一旦功能发生变化,就必须冒着更新两个文件中代码的风险,这违反了DRY原则。相反,过多的props传值会很快变得混乱,迫使维护者(即使这个人是你)在使用组件时要理解一大段上下文,拖慢编写速度。使用混合。Vue中的Mixins对于编写函数式风格的代码很有用,因为函数式编程就是通过减少移动部分来使代码更易于理解(引用自MichaelFeathers)。Mixin允许您封装一些功能,供您的应用程序的其他组件使用。如果使用得当,它们不会改变函数范围之外的任何东西,所以即使多次执行,只要是同一个输入,总是可以得到相同的值。真的很强大!基础示例我们有一对不同的组件,它们的功能是通过切换状态(布尔类型)来显示或隐藏模态框或提示框。这些工具提示框和模态框除了功能相似之外没有任何共同点:外观不同,使用方式不同,但逻辑是一样的。//模态框constModal={template:'#modal',data(){return{isShowing:false}},methods:{toggleShow(){this.isShowing=!this.isShowing;}},components:{appChild:child}}//提示框constTooltip={template:'#tooltip',data(){return{isShowing:false}},methods:{toggleShow(){this.isShowing=!this.isShowing;}},components:{appChild:Child}}在这里我们可以提取逻辑并创建可以重复使用的项目:consttoggle={data(){return{isShowing:false}},方法:{toggleShow(){this.isShowing=!this.isShowing;}}}constModal={template:'#modal',mixins:[toggle],组件:{appChild:Child}};constTooltip={template:'#tooltip',mixins:[toggle],组件:{appChild:孩子}};您可以单击此处查看SarahDrasner(@sdras)在CodePen上编写混合宏的示例。为了更容易理解mixin,这个例子有意简单化。Mixin在实际应用中有以下应用,但它的作用不仅限于此:获取窗口和组件的大小,收集特定的鼠标事件和图表的基本元素。PaulPflugradt有一个关于VueMixins的优秀项目,值得一提的是它是用coffeescript编写的。用法上面的codepen例子并没有告诉我们如何在真实的应用中使用Mixin,下面我们来看一下。您可以按照自己喜欢的任何方式设置目录结构,但为了结构起见,我喜欢创建一个新的mixin目录。我们创建的文件具有.js扩展名(与.vue不同,就像我们的其他文件一样),为了使用mixin,我们需要导出一个对象。那么我们就可以在Modal.vue中使用这种写法来引入这个Mixin:importChildfrom'./Child'import{toggle}from'./mixins/toggle'exportdefault{name:'modal',mixins:[toggle],components:{appChild:Child}}重要的是要了解即使我们使用的是对象而不是组件,生命周期函数仍然对我们可用。我们这里也可以使用mounted()钩子函数,它会应用在组件的生命周期上。这种工作方式非常灵活和强大。结合下面的例子,我们可以看到,我们不仅实现了我们想要的功能,而且Mixin中的生命周期钩子也是可用的。因此,当我们在组件上应用Mixin时,有可能组件和Mixin都定义了相同的生命周期钩子,这时候钩子的执行顺序问题就凸显出来了。默认情况下会先注册Mixin,然后再注册组件,这样我们就可以根据需要在组件中重写Mixin中的语句。组件说了算。当发生冲突并且组件必须“决定”哪个获胜时,这一点尤其重要,否则,所有内容都在数组中执行,mixin将首先被推入数组,然后是组件。//mixinconsthi={mounted(){console.log('hellofromVueinstance!')}}//vueinstanceorcomponentnewVue({el:'#app',mixins:[hi],mounted(){console.log('hellofromVueinstance!')}});//控制台输出>hellofrommixin!>hellofromVueinstance!如果这两者冲突,让我们看看Vue实例或组件如何决定赢家://mixinconsthi={methods:{sayHello:function(){console.log('hellofrommixin!')}},mounted(){this.sayHello()}}//vueinstanceorcomponentnewVue({el:'#app',mixins:[hi],methods:{sayHello:function(){console.log('hellofromVueinstance!')}},mounted(){this.sayHello()}})//控制台输出>hellofromVueinstance!>hellofromVueinstance!你可能已经注意到它有两个console.logs而不是一个-这是因为当第一个函数被调用时,它并没有被销毁,它只是被重写了。我们在这里调用了sayHello()函数两次。全局Mixin当我们用“全局”来描述Mixin时,我们并不意味着Mixin可以在每个组件中访问,例如filter。只不过我们可以通过mixins:[toggle]访问组件上的Mixin对象。每个单独的组件都注册了一个全局mixin。因此,它们的使用场景极其有限,我们在使用时需要格外小心。我能想到的一种用途是类似于插件,您需要让它访问所有内容。但即使在这种情况下,我也会对您正在做的事情保持警惕,特别是如果您要向您的应用程序添加功能,并且这样做可能对您来说就像一个潘多拉魔盒。要创建全局实例,我们可以将其放在Vue实例之上。在典型的Vue-cli初始化项目中,它可能在您的main.js文件中。Vue.mixin({mounted(){console.log('hellofrommixin!')}})newVue({...})再次强调,谨慎使用!该console.log将出现在每个组件上,在这种情况下还不错(除了控制台上的冗余输出)。但是如果全局mixin使用不当,你就会看到它有多可怕。结论Mixins对于封装一小段您想要重用的代码很有用。Mixins当然不是您唯一可行的选择:例如,高阶组件允许您组合相似的功能,而Mixins只是实现它们的一种方式。我喜欢mixins,因为我不需要传递状态,但当然这种模式可能会被滥用,所以请仔细考虑哪个选项对您的应用程序最有意义!