VueJS核心组件如何避免class与style属性继承?
Vue组件禁止继承class和style属性的解决方案
在开发Vue组件时,你肯定遇到过这个场景:Vue默认会自动继承非Prop属性,这对data-*这类属性来说很友好,但如果我们希望核心组件的样式完全由自身样式文件控制,不想外部传入的class和style随意修改组件布局,那就得特殊处理——毕竟官方提供的inheritAttrs: false选项,并不影响class和style的自动绑定。
我试过的不太理想的方案
最开始我想到在组件挂载后,强制重置根元素的类名,代码大概是这样:
<template> <div ref="root" class="hello">Hi</div> </template> <script> export default { mounted() { this.$refs.root.className = 'hello' } } </script>
但这种方式在组件依赖自身属性动态生成样式的复杂场景下,维护起来特别麻烦,比如下面这个根据type属性切换不同状态类的组件:
Vue.component('my-feedback', { props: ['type'], data: function(){ var vm = this; return { classes: { 'my-feedback-info': vm.type === 'info', 'my-feedback-note': vm.type === 'note', 'my-feedback-warning': vm.type === 'warning', 'my-feedback-success': vm.type === 'success' } }; }, template: ` <div class="my-feedback" :class="classes"> <slot></slot> </div> ` });
用手动重置类名的方法,很容易和组件自身的动态样式逻辑冲突,完全不适合复杂组件。
可行的解决办法
Vue 2.x 版本
后来我在Vue社区的聊天频道里找到了靠谱的方案,核心是用渲染函数(render function)手动控制根元素的属性,把外部传入的class和style完全过滤掉:
Vue.component('my-feedback', { props: ['type'], inheritAttrs: false, // 先关闭非Prop属性的自动继承 render(h) { // 只保留我们需要的属性,过滤掉class和style const attrs = {} for (const key in this.$attrs) { if (key !== 'class' && key !== 'style') { attrs[key] = this.$attrs[key] } } const classes = { 'my-feedback': true, 'my-feedback-info': this.type === 'info', 'my-feedback-note': this.type === 'note', 'my-feedback-warning': this.type === 'warning', 'my-feedback-success': this.type === 'success' } return h('div', { class: classes, attrs: attrs }, this.$slots.default) } })
这样一来,不管外部怎么传class或style,都不会影响组件根元素的样式,同时data-*这类有用的非Prop属性还能正常继承,完美满足需求。
Vue 3.x 版本
到了Vue 3,官方直接优化了这个问题!只需要设置inheritAttrs: false,就能完全禁止所有属性(包括class和style)的自动继承,代码简洁多了:
<template> <div class="my-feedback" :class="classes"> <slot></slot> </div> </template> <script> export default { props: ['type'], inheritAttrs: false, // 直接禁用所有属性继承 computed: { classes() { return { 'my-feedback-info': this.type === 'info', 'my-feedback-note': this.type === 'note', 'my-feedback-warning': this.type === 'warning', 'my-feedback-success': this.type === 'success' } } } } </script>
如果之后需要手动处理某些特定属性,还可以通过$attrs访问并选择性绑定到元素上,灵活性拉满。
内容的提问来源于stack exchange,提问作者Awan
相关产品推荐
相关产品推荐

