1. 问题
使用 Taro 开发微信小程序的时候,将原来的 main.js
页面拆分为多个函数式组件的时候,发现 main.js
已经引入的 scss
文件里面的类,在自定义组件中不生效
2. 解决:
查阅 Taro 文档及微信小程序文档发现如下:
自定义组件对应的样式文件,只对该组件内的节点生效。编写组件样式时,需要注意以下几点:
- 组件和引用组件的页面不能使用
id 选择器(#a)
、属性选择器([a])
和标签名选择器
,请改用class 选择器
。 - 组件和引用组件的页面中使用
后代选择器(.a .b)
在一些极端情况下会有非预期的表现,如遇,请避免使用。 - 子元素选择器
(.a > .b)
只能用于 View 组件与其子节点之间,用于其他组件可能导致非预期的情况。 -
继承样式
,如font
、`color,会从组件外(父组件)继承到组件内。但是引用组件时在组件节点上书写的 className 无效。(具体解决方案请参见下面的外部和全局样式介绍。) - 除继承样式外,
app.scss
中的样式、引入组件所在页面的样式,均对自定义组件无效。
#a { } /* 在组件中不能使用 */
[a] { } /* 在组件中不能使用 */
button { } /* 在组件中不能使用 */
.a > .b {} /* 除非 .a 是 view 组件节点,否则不一定会生效 */
真香,原来是第 2 点的原因,本人使用了后代选择器,父类
是在 原页面
,而 子类
是在 自定义组件
中,所以子类样式并不会生效。
3. 解决自定义组件样式使用问题
3.1 自定义组件制定默认样式
组件可以指定它所在节点的默认样式,使用 :host
选择器。只需要在样式文件中输入该选择器,立即生效,非常好用,亲测有效
/* 该自定义组件的默认样式 */
:host {
color: red;
font-weight: bold;
font-size: 30PX;
}
3.2 externalClasses 定义若干个外部样式类
MyPage.js
export default class MyPage extends Component {render () {return <CustomComp my-class="red-text" />}
}
MyPage.scss
.red-text {color: red;}
CustomComp.js
export default class CustomComp extends Component {static externalClasses = ['my-class']
render () {return <View className="my-class"> 这段文本的颜色由组件外的 class 决定 </View>}
}
上面的 CustomComp 使用了 ES6 extends 来创建了组件,那么问题来了,如果是 函数式组件
,那该如何写呢?哈哈很简单
export default function CustomComp (props){CustomComp.externalClasses = ['my-class']
render () {return <View className="my-class"> 这段文本的颜色由组件外的 class 决定 </View>}
}
注意:
externalClasses
需要使用短横线命名法 (kebab-case)
,而不是 React 惯用的 驼峰命名法 (camelCase)。否则无效。
3.3 全局样式类
使用外部样式类可以让组件使用制定的组件样式类,如果希望组件外样式类能够完全影响组件内部吗可以将组件构造器中的options.addGlobalClass
字段置为 true
CustomComp.js
export default class CustomComp extends Component {
static options = {addGlobalClass: true}
render () {return <View className="red-text"> 这段文本的颜色由组件外的 class 决定 </View>}
}
组件外的样式定义
.red-text {color: red;}
如果使用函数式组件
...
CustomComp.options = {addGlobalClass: true}
...
总结
1. 解决了自定义组件(引用页面)样式不生效的问题
2. 可以使用:host
来写默认样式
3. 可以选择使用外部的特定样式类或者全局样式类,不同的组件写法略微不同