在vue实际开发的项目中。 经常会遇到封装的组件需要改变样式的情况。 这时候, 如果改变样式的方式不当就会对封装的组件造成污染。 如果组件内部对基本样式的封装不够合理。 又容易造成调用组件时过多的处理样式问题。 这些都是不合理的。 本文讨论父组件修改子组件的样式, 可以在有不同的样式需求的时候根据选择游刃有余的去处理。 这里以公共的title组件为例解释。
1. 修改class
可以直接传递class名给子组件。 或者根据布尔的true或false来显示隐藏class名。
2. 修改style
可以根据对象键值对去修改style样式。 由于style的优先级较高。 所以往往可以更改样式。 在子组件中定义好键名, 父组件中传入键值就可以更改子组件的属性了。 也可以直接在父组件中写style对象。 传入子组件, 这样就不必再在子组件中提前写好键值, 方便对一些不常用的属性的修改(注意: 由于对象的特性, 如果对象名相同。 后面的对象会覆盖前面的对象, 所以尽量将customStyle放入后面)。
3. 使用computed来获取计算后的属性
可以根据props传入的参数, 来获取计算属性计算后的样式。
4. 使用穿透
由于vue的scoped具有单页面样式保护特性。 所以可以使用穿透 ::v-deep
去修改子组件中的样式
语法: 父组件class :: v-deep 子组件class
5. 父组件使用特殊style写法(重要, 这样子组件中js和css都可以处理父组件传入的变量)。
原理: 父组件通过style方式传入子组件变量。 子组件根据变量改变颜色。
// 父组件
style="--lc: pink"
// 子组件
$dfColor: lightblue;
background: var(--lc, $dfColor); // 第二个参数为默认变量值
6. 利用javascript去改变子组件的样式
需要在this.$nextTick之后才能获取到子组件的dom。 然后操作dom去修改子组件的样式。 也可以先在子组件中定义好函数, 然后通过父组件调用子组件的函数去改变子组件的样式。
created() {
this.$nextTick(() => {
let ele = this.$refs.titleRef;
let pp = ele.$el.getElementsByTagName('p')[0];
pp.style.background = "red"
})
},
7. 看代码
- 父组件
// 父组件
<template>
<div>
<g-title
t="测试哈"
class="aa"
ref="titleRef"
cc="cc"
borderBottom
style="--lc: blue;"
:customStyle="myStyle"
></g-title>
</div>
</template>
<script>
export default {
name: "Test1",
data() {
return {
myStyle: {
fontSize: '100px',
}
};
},
created() {
// 这里必须等dom更新完毕才可以操作dom
this.$nextTick(() => {
let ele = this.$refs.titleRef;
let pp = ele.$el.getElementsByTagName('p')[0];
pp.style.background = "red"
})
},
};
</script>
- 子组件
<!--
* @描述
* 公共title组件。可以设置title, 可以设置左侧竖条颜色
* @使用方法
* <g-title t="4. 回到顶部"></g-title> <g-title t="左侧粉色" style="--lc: pink"/>
*
<g-title
t="测试哈"
class="aa"
ref="titleRef"
cc="cc"
borderBottom
style="--lc: pink;"
:customStyle="myStyle"
></g-title>
* @LastEditTime: 最后更新时间
* 2021-10-30
-->
<template>
<div
v-if="title || t"
class="bb"
>
<p
class="title"
:class="{'has-border':borderBottom, cc}"
:style="[{color: color}, customStyle, setBorderRadius]"
data-color="blue"
>{{title || t}}</p>
</div>
</template>
<script>
let cl = "yellow";
export default {
name: "GTitle",
props: {
title: {
type: String,
default: ''
},
color: {
type: String,
default: '',
},
t: {
type: String,
default: ''
},
cc: {
type: String,
default: ''
},
other: {
},
customStyle: {
type: Object,
default: () => { },
},
borderBottom: {
type: Boolean,
default: false,
},
br: {
type: String,
default: '20',
}
},
computed: {
setBorderRadius() {
let obj = {};
// 这里可以根据var(--lc)得到父组件传入变量的值。 如果--lc没值, 就取第二个参数的值
if (this.br) {
obj = {
borderRadius: this.br + 'px',
borderTop: this.br + 'px solid var(--lc, yellow)'
}
}
return obj;
}
},
};
</script>
<style scoped lang='scss'>
$dfColor: lightblue;
.title {
width: 100%;
height: 28px;
padding-left: 22px;
line-height: 28px;
position: relative;
margin: 20px 0;
font-weight: 600;
box-sizing: border-box;
color: var(--cl, $dfColor); // 如果不传--cl。 默认使用第二个参数的变量
}
.title::before {
position: absolute;
top: 3px;
bottom: 0;
left: 0;
content: "";
width: 6px;
height: 22px;
z-index: 1;
background-color: var(--lc, $dfColor); // 左侧的竖条颜色
}
.has-border {
border-bottom: 1px solid var(--lc, $dfColor);
}
.cc {
margin: 100px;
}
</style>