样式绑定
绑定 class
Vue 最好不要亲手操作 DOM
- 字符串写法(个数一个,名字不确定)
<div id="root">
<div class="basic" :class="mood" @click="change"></div>
</div>
<script>
const app = Vue.createApp({
el: '#root',
data() {
return {
value: 100,
mood: 'normal'
}
},
methods: {
change(){
this.mood = 'happy'
}
},
})
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
其中 :class 里面的是 Vue 实例中的变量,该变量的值才是元素真实的 class,Vue 编译后会将变量替换合并至前面的 class 里面:
适用于样式的类名会切换
- 如果元素后续会添加很多个样式:绑定一个数组(个数不确定,名字不确定)
<div id="root">
<div class="basic" :class="classArr" @click="change"></div>
</div>
<script>
const app = Vue.createApp({
el: '#root',
data() {
return {
classArr: ['class1', 'class2']
}
},
})
</script>
2
3
4
5
6
7
8
9
10
11
12
13
- 还可以是一个对象(个数确定,名字也确定)
<div id="root">
<div class="basic" :class="classObj" @click="change"></div>
</div>
<script>
const app = Vue.createApp({
el: '#root',
data() {
return {
classObj: {
class1: false,
class2: true // true表示添加该类,false不添加
}
}
},
})
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
style 也可以交给 Vue 来动态绑定,需要改为多单词大小写模式
绑定图片路径(静态, 动态)
静态绑定
在布局时直接写好图片或背景的路径。
在 html 中设置 img 的 src 属性
<div> <img src="../assets/images/1.jpeg" /> </div>
1
2
3在 css 中设置 background 属性
<div> </div> <style> div{ background: url('../assets/images/1.jpeg') no-repeat; </style>
1
2
3
4
5
6
7在 data 中声明,并在模板中绑定
export default { data() { return { // 顶部导航背景图片配置 background: { // 背景图片地址 backgroundImage: 'url(' + require('../../../static/img/person/temp1.png') + ')', // 背景图片是否重复 backgroundRepeat: 'no-repeat', // 背景图片大小 backgroundSize: 'cover', // 背景颜色 backgroundColor: '#000', // 背景图片位置 backgroundPosition: 'center top', }, } }, }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
可以看到不管是在 html 中引入或在 css 中引入图片都会被解析成 base64 编码,打包之后 dist 文件夹中也不会有图片,而是在压缩文件中存储 base64 编码。
对图片编码的原因
加载一张图片就需要发送一次 http 请求,当图片过多时会降低页面性能,因此 webpack 引入了 url-loader
解决这个问题。
- url-loader 会对引入的图片编码,生成 dataURI 。相当于把图片数据翻译成一串字符,再把这些字符打包到文件当中,最终只需要引入这个文件就可以访问图片。
- 当然如果图片较大,编码也会消耗性能,因此
url-loader
提供了一个limit
参数,小于 limit 字节的文件会被转为dataURl
,大于 limit 的还是会使用file-loader
进行 copy,一般会放在 static 文件夹下面。
url-loader 和 file-loader 关系
简单的将,url-loader 封装了 file-loader。打包时 url-loader 的工作分两种情况:
- 文件大小小于 limit 参数,url-loader 会把文件转为 dataURL;
- 文件大小大于 limit,url-loader 会调用 file-loader 进行处理,参数也会直接传给 file-loader,file-loader 将图片拷贝到 static 文件夹下。
动态绑定
将图片的路径绑定在一个 js 变量里,运行时动态绑定。
按照之前的写法会报错
<div>
<img :src="img" />
</div>
<script>
export default {
data() {
return {
img: '../assets/images/1.jpeg',
}
},
}
</script>
2
3
4
5
6
7
8
9
10
11
12
webpack 引入才可以
用 require 或 import 就可以正常展示,并且最终效果跟在 html 中或者 css 中直接绑定效果是一样的。
require
<div> <img :src="img" /> </div> <script> export default { data() { return { img: require('../assets/images/1.jpeg'), } }, } </script>
1
2
3
4
5
6
7
8
9
10
11
12import
<div> <img :src="img" /> </div> <script> import img1 from '../assets/images/1.jpeg' export default { data() { return { img: img1, } }, } </script>
1
2
3
4
5
6
7
8
9
10
11
12
13
原因
使用不同的方式设置图片源,webpack 对他们的处理方式也是不同的:
- 使用
import
或者require
或者静态绑定
都会被 webpack 的 url-loader 当做依赖模块处理; - 如果是直接写在 js 中,因为 js 是动态的,所以 webpack 不会处理的,打包后也不会显示在 dist 目录中。
直接放在 static 文件夹下
第三种情况,图片放在 static 文件夹下面,在 html、css、js 中直接引入,可以发现图片都可以正常展示。
webpack 只能处理静态资源。assets 和 static 两个文件都是静态的,但是它们是有区别的
static
文件夹下面的文件是无法被 webpack 处理的,必须使用绝对路径来引用这些文件。其他地方的文件或图片都可以被 webpack 解析成模块依赖,这时候就可以用 url-loader 和 css-loader 去处理。
如果在 js 中直接返回图片地址,因为 js 是动态的,所以 webpack 不会去处理。
但是可以使用 require 或 import 将图片当成模块加载进来,这样就会被 webpack 当成静态文件解析,然后就可以被 url-loader 处理。
关于~(准确性未知)
当这样引入出现错误时
需要改为:
个人理解: url 中的不会被当做静态资源引入??(待验证)
原因:
webpack 资源处理的规则分为:
- 相对路径:没有前缀的路径;
- 带
~
的路径:相对根目录的路径
没看懂
// 相对路径:
'./assets/start.png'
'assets/start.png' // 没有前缀的路径,被webpack解析为相对路径
// 带~的路径 动态引入
'~@/assets/theme/start.png' // 被webpack解析为 require(src/assets/theme/start.png) @在webpack 被resolve.alias配置成等价于 /src
// 相对根目录的路径
'/assets/start.png' //webpack不解析
2
3
4
5
6
7
8
9
样式 scoped 与样式穿透
scoped
作用**:防止全局同 css 类名样式的污染**。style 标签使用scoped
后, style 标签里的样式只会作用于该组件(第三方组件库如 Element-UI 内部组件就不会被影响),而不会渗透到子组件中(除了子组件的根节点)。
所以一个子组件的根节点会同时受其父组件的 scoped CSS 和子组件的 scoped CSS 的影响。这样设计是为了让父组件可以从布局的角度出发,调整其子组件根元素的样式。
实现原理
在 html 标签上添加data-v-xxxxxxxx
属性,然后在 css 类名后添加属性选择器,即利用 css 类选择 + 属性选择器实现样式局部化:
// 原始文本
<template>
<div class="parent">
我是来自父组件的
</div>
</template>
<style lang="scss" scoped>
.parent {
color: #333;
}
</style>
2
3
4
5
6
7
8
9
10
11
12
// 转换后的
<template>
<div data-v-2f3286d4 class="parent"> // 这里加了个data-v-....属性
我是来自父组件的
</div>
</template>
<style>
.parent[data-v-2f3286d4] { // 这里通过类+属性选择器来选择
color: #333;
}
</style>
2
3
4
5
6
7
8
9
10
11
12
父组件有 scoped,子组件无 scoped 的详细步骤:
- 父组件中的元素以及子组件中的根元素都会被加上
data-v-xxxxxxxx
属性 - 将添加了
scoped
的 style 中的样式编译为类名加属性选择器的样式(.classname[data-v-xxxxxxxx]) - 子组件中的样式因为未添加这样的属性而无法被选择器选择到,只能使用子组件中的原始的样式。
通常的情况是父组件(我们写的)加 scoped,公共组件或第三方库不加 scoped
更多细节:Vue 中 scoped 属性浅析 - 韩帅 - 博客园 (cnblogs.com) (opens new window)
scoped 穿透
在 Vue 项目中,当我们引入第三方组件库时,有时需要局部修改第三方组件库中子元素的样式,而又不想去除 scoped 属性,以免造成组件之间的样式覆盖。这时我们可以通过特殊的方式穿透 scoped。有以下一些方法
>>>
如果项目使用的是 css 原生样式,可以直接使用 >>>
进行修改
外层 >>> 第三方组件{
样式
}
/* 编译前 */
<style scoped>
.a >>> .b {
/* ... */
}
/* 编译后 */
.a[data-v-f3f3eg9] .b {
/* ... */
}
</style>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/deep/
项目中如果使用了预处理器: scss 、sass、less 等, 操作符 >>>
可能会因为无法编译而报错。此时可以使用 /deep/ 进行穿透。
注意:vue-cli3 以上版本废弃该用法
外层 /deep/ 第三方组件 {
样式
}
<style lang="scss" scoped>
/* 用法1 */
.a {
/deep/ .b {
/* ... */
}
}
/* 用法2 */
.a /deep/ .b {
/* ... */
}
</style>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
::v-deep
如果使用了预处理器都可以使用 ::v-deep
,但现在(2022 年 5 月 9 日 21:27:32)貌似又不推荐了,在新的 vue3.0 单文件规范中 ::v-deep
写法已经被废弃了
<style lang="scss" scoped>
/* 用法1 */
.a{
::v-deep .b {
/* ... */
}
}
/* 用法2 */
.a ::v-deep .b {
/* ... */
}
</style>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
:deep
现在用 ::v-deep
会报错,推荐使用 ****:deep(<inner-selector>)
。**报错如下:
[@vue/compiler-sfc]::v-deep usage as a combinator has been deprecated. Use :deep(<inner-selector>) instead.
:deep(.el-form-item) {
margin-bottom: 23px;
@height: 45px;
}
2
3
4