chenjunda
长期主义

diary2025-10-29

2025-11-05 思考感悟

实习日记

1,在使用element组件的时候,要记得配置参数

这些东西不需要死记硬背,只需要看文档就可以了。但是要注意在设置参数的时候有时候需要用冒号设置,进行数据的绑定,有的参数想写死就不需要加冒号,只需要写在引号里面就可以了

1
2
3
4
5
6
7
8
9
10
<el-upload ref="uploadRef" class="upload-demo" drag action="#" :on-change="uploadChange" :file-list="fileList"
:auto-upload="false" :multiple="false" accept=".xls,.xlsx">
<i class="el-icon-upload"></i>
<div class="el-upload__text">
将文件拖到此处,或<em>点击上传</em>
</div>
<div class="el-upload__tip" slot="tip">
支持上传.xlsx/.xls文件
</div>
</el-upload>

就好比这一段,action我不想使用,我就写死为‘#’,但是on-change我想在进行文件类型判断的时候使用,就要绑定一个方法

1
2
3
4
5
6
7
8
9
10
11
12
// 文件上传前的验证
uploadChange(file) {
console.log(file)
const fileExtension = file.name.split('.').pop().toLowerCase();
const isExcelFile = fileExtension === 'xlsx' || fileExtension === 'xls';
if (!isExcelFile) {
this.$message.error('只能上传 .xlsx/.xls 格式的文件!');
this.fileList = []
return false;
}
this.fileList = [file]
},

2,element组件插槽的使用

这里就好比拿el-dialog举例子,在element的官方文档中写:

需要设置visible属性,它接收Boolean,当为true时显示 Dialog。Dialog 分为两个部分:bodyfooterfooter需要具名为footerslottitle属性用于定义标题,它是可选的,默认值为空。最后,本例还展示了before-close的用法。

1
2
3
4
5
6
7
8
9
10
11
12
13
<el-button type="text" @click="dialogVisible = true">点击打开 Dialog</el-button>

<el-dialog
title="提示"
:visible.sync="dialogVisible"
width="30%"
:before-close="handleClose">
<span>这是一段信息</span>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="dialogVisible = false">确 定</el-button>
</span>
</el-dialog>

也就是说这里默认的组件footer区域只有确定和取消两个按钮,如果我想新增按钮,就必须使用插槽

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!-- 底部操作栏 -->
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="downloadTemplate" class="template-btn">
模板下载
</el-button>
<div>
<el-button @click="showUploadDialog = false" class="cancel-btn">
取消
</el-button>
<el-button type="primary" @click="handleUploadConfirm" class="confirm-btn">
确定
</el-button>
</div>
</div>

3,下载文件部分代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 下载模板文件
downloadTemplate() {
var data = {
file: 'temp/用户信息导入模板.xlsx',
name: '用户信息导入模板.xlsx'
}

downloadFileNew(data.file).then(resFile => {
const url = window.URL.createObjectURL(resFile)
const a = document.createElement('a')
a.href = url
a.download = data.name
a.click()
window.URL.revokeObjectURL(url)
})
},

其中downloadFileNew是在api中封装好的js文件,可以直接导入使用

1
2
3
4
5
6
7
// 文件下载
export function downloadFile(params) {
return request({
url: '/yyptfile/' + params,
method: 'get',
responseType: 'blob'
})
1
const url = window.URL.createObjectURL(resFile)
  • 功能: 将Blob数据转换为临时URL

  • 作用: 让浏览器可以访问内存中的文件数据

  • Blob 是什么

    Blob 对象表示不可变的、原始数据的类文件对象。可以把它理解为:

    • 二进制数据容器:存储二进制数据
    • 类文件对象:像文件一样有类型和大小
    • 不可变数据:创建后内容不能直接修改
  • createObjectURL(): 创建指向内存中文件的临时URL

1
2
3
const a = document.createElement('a')
a.href = url
a.download = data.name
  • 功能: 创建隐藏的 <a> 标签并设置下载属性
  • createElement('a'): 创建链接元素
  • href: 设置文件URL
  • download: 设置下载后的文件名
1
a.click()
  • 功能: 程序化触发链接点击,开始下载
  • 用户无需手动点击,代码自动触发下载
1
window.URL.revokeObjectURL(url)
  • 功能: 释放创建的临时URL,避免内存泄漏
  • 重要: 每次创建createObjectURL后都必须调用revokeObjectURL

4,文件上传前的验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 文件上传前的验证
uploadChange(file) {
console.log(file)
const fileExtension = file.name.split('.').pop().toLowerCase();
const isExcelFile = fileExtension === 'xlsx' || fileExtension === 'xls';
if (!isExcelFile) {
this.$message.error('只能上传 .xlsx/.xls 格式的文件!');
this.fileList = []
return false;
}
this.fileList = [file]
},


1
const fileExtension = file.name.split('.').pop().toLowerCase();
  • 分解步骤:
    • file.name: 获取文件名(如:”用户数据.xlsx”)
    • .split('.'): 按点号分割成数组 ["用户数据", "xlsx"]
    • .pop(): 取数组最后一个元素 "xlsx"
    • .toLowerCase(): 转换为小写 "xlsx"(避免大小写问题)

5,前端向后端传送文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 确定按钮点击事件
handleUploadConfirm() {
console.log(this.fileList)
if (this.fileList.length === 0) {
this.$message.warning('请先选择要上传的文件');
return;
}
const formData = new FormData()
formData.append('file', this.fileList[0].raw)
importUsers(formData).then(ref => {
if (ref) {
if (ref.success) {
this.$message({
message: '导入成功!',
type: 'success',
duration: 2000
})
} else {
this.$message({
message: ref.message,
type: 'error',
duration: 2000
})
}
}
})
},
1
2
const formData = new FormData()
formData.append('file', this.fileList[0].raw)
  • FormData: 用于构建表单数据的API,适合文件上传
  • this.fileList[0].raw: 获取文件列表中的第一个文件的原始文件对象
  • append('file', file): 将文件添加到formData中,字段名为’file’

6,css样式

不加 scoped 的问题(全局样式)
1. 样式污染(样式泄露)

css

1
2
3
4
/* 不加 scoped - 全局生效 */
.button {
background: red;
}

这个 .button 样式会影响整个项目中所有使用 .button 类的元素。

2. 样式冲突

如果多个组件都定义了相同的类名:

css

1
2
3
4
5
/* ComponentA.vue */
.title { color: blue; }

/* ComponentB.vue */
.title { color: red; }

后加载的样式会覆盖先加载的,导致不可预期的效果。

3. 难以维护
  • 不知道样式在哪里被使用
  • 修改一个地方可能影响其他地方
  • 团队协作时容易产生冲突
为什么 scoped 无法影响 Element UI 组件
问题原因

Element UI 组件内部的 HTML 结构是在组件内部渲染的,不会带有你当前组件的 data-v-xxxxx 属性。

示例:

html

1
2
3
4
5
6
7
8
9
<!-- 你的组件 -->
<div class="custom-upload-dialog" data-v-12345>
<el-dialog>
<!-- Element UI 内部渲染的HTML,没有 data-v-12345 -->
<div class="el-dialog__header">
...
</div>
</el-dialog>
</div>
解决方案:使用深度选择器
Vue 2 中的写法
方法一:使用 >>>(Sass 中不适用)

css

1
2
3
4
5
<style scoped>
.custom-upload-dialog >>> .el-dialog__header {
padding: 16px 20px;
}
</style>
方法二:使用 /deep/

css

1
2
3
4
5
<style scoped>
.custom-upload-dialog /deep/ .el-dialog__header {
padding: 16px 20px;
}
</style>
方法三:使用 ::v-deep(推荐)

css

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<style scoped>
.custom-upload-dialog ::v-deep .el-dialog__header {
padding: 16px 20px;
border-bottom: 1px solid #ebeef5;
}

.custom-upload-dialog ::v-deep .el-dialog__body {
padding: 20px;
padding-top: 0%;
padding-bottom: 0%;
}

.custom-upload-dialog ::v-deep .el-dialog__footer {
padding: 16px 20px;
border-top: 1px solid #ebeef5;
}

/* 上传组件样式 */
.custom-upload-dialog ::v-deep .el-upload {
width: 100%;
display: block;
}

.custom-upload-dialog ::v-deep .el-upload-dragger {
width: 100% !important;
}

.custom-upload-dialog ::v-deep .el-upload-dragger:hover {
border-color: #409eff;
}

.custom-upload-dialog ::v-deep .el-upload-list {
margin-top: 10px;
width: 100%;
}

.custom-upload-dialog ::v-deep .el-icon--upload {
font-size: 48px;
color: #c0c4cc;
margin: 20px 0;
}

.custom-upload-dialog ::v-deep .el-upload__text {
font-size: 14px;
color: #606266;
text-align: center;
margin: 0 10px;
}

.custom-upload-dialog ::v-deep .el-upload__text em {
color: #409eff;
font-style: normal;
}

.custom-upload-dialog ::v-deep .el-upload__tip {
font-size: 12px;
color: #909399;
text-align: center;
margin-top: 10px;
}
</style>
Vue 3 中的写法

Vue 3 推荐使用 :deep()

css

1
2
3
4
5
<style scoped>
.custom-upload-dialog :deep(.el-dialog__header) {
padding: 16px 20px;
}
</style>
<p> 标签(段落)
  • 语义:表示一个段落(paragraph)
  • 用途:用于文本内容的分段
  • 示例

html

1
2
<p>这是第一个段落。包含完整的思路或内容块。</p>
<p>这是第二个段落。与前一段在内容上有明显的分隔。</p>
<span> 标签(内联)
  • 语义:没有特定语义,是通用的内联容器
  • 用途:用于对文本中的一部分进行样式化或操作
  • 示例

html

1
<p>这是一段文字,其中<span class="highlight">这部分需要高亮</span>显示。</p>
显示特性区别
<p> 标签
  • 块级元素:独占一行
  • 默认样式:有上下外边距(margin)
  • 自动换行:前后会自动换行
<span> 标签
  • 内联元素:不会打断文本流
  • 默认样式:无特殊样式
  • 不换行:前后不会换行
视觉对比

html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- p 标签示例 -->
<p>第一段落</p>
<p>第二段落</p>
<!-- 显示效果:
第一段落
← 这里有间距
第二段落
-->

<!-- span 标签示例 -->
<span>第一个span</span>
<span>第二个span</span>
<!-- 显示效果:
第一个span第二个span
-->
在代码中的应用

html

1
2
3
4
5
6
7
8
9
10
11
<!-- 你现在的写法 -->
<p class="attachment-label">
<span class="required-star">*</span>
<span class="attachment-text">附件</span>
</p>

<!-- 为什么这样设计: -->
<!--
p 标签:表示这是一个独立的文本段落
span 标签:用于对段落中的 "*""附件" 分别进行样式控制
-->
嵌套规则
允许的嵌套:

html

1
2
<p>段落中的<span>内联内容</span></p>
<div><p>段落</p></div>
不允许的嵌套:

html

1
2
3
4
5
<!-- 错误!p 标签不能嵌套 p 标签 -->
<p><p>嵌套段落</p></p>

<!-- 错误!p 标签不能嵌套 div 等块级元素 -->
<p><div>块级元素</div></p>
element样式不生效问题

当我们想修改的组件部分层级为总组件的子部分的时候,使用::v-deep就可以解决

1
2
3
4
.custom-upload-dialog ::v-deep .el-upload__text em {
color: #00BCB6;
font-style: normal;
}

就好比这样,em所在的部分为el-upload的子部分,也就是自定义的el-upload__text,这样就可以使用这样的写法来进行样式穿透(注意::v-deep前面有一个空格!!)

1
2
3
4
5
6
7
8
9
10
11
12
13
<div class="dialog-content">
<p class="attachment-label"><span class="required-star">*</span><span class="attachment-text">附件</span></p>
<el-upload ref="uploadRef" class="upload-demo" drag action="#" :on-change="uploadChange" :file-list="fileList"
:auto-upload="false" :multiple="false" accept=".xls,.xlsx">
<i class="el-icon-upload"></i>
<div class="el-upload__text">
将文件拖到此处,或<em>点击上传</em>
</div>
<div class="el-upload__tip custom-tip" slot="tip">
支持上传.xlsx/.xls文件
</div>
</el-upload>
</div>

但是当所在的模块和组件属于同一级别的模块,就不可以这样写,这样只适用于子模块

就好比这里的按钮自定义的class和element封装的el-button–primary的class是同一级别

1
2
3
<el-button type="primary" @click="handleUploadConfirm" class="confirm-btn">
确定
</el-button>
1
2
3
4
5
6
.confirm-btn {
background-color: #00BCB6 !important;
border-color: #00BCB6 !important;
}

:deep(.el-button--primary).confirm-btn {}

这时候就需要使用::deep强行将el-button–primary穿透给自定义的类confirm-btn

Author: chenjunda

Link: http://example.com/2025/11/05/diary2025-10-29/

Copyright: All articles in this blog are licensed under CC BY-NC-SA 3.0 unless stating additionally.

< PreviousPost
189.轮转数组
NextPost >
diary2025-10-30
CATALOG
  1. 1. 实习日记
    1. 1.0.0.1. 1,在使用element组件的时候,要记得配置参数
    2. 1.0.0.2. 2,element组件插槽的使用
    3. 1.0.0.3. 3,下载文件部分代码
  • 1.1. Blob 是什么
    1. 1.1.0.1. 4,文件上传前的验证
    2. 1.1.0.2. 5,前端向后端传送文件
    3. 1.1.0.3. 6,css样式
      1. 1.1.0.3.1. 不加 scoped 的问题(全局样式)
        1. 1.1.0.3.1.1. 1. 样式污染(样式泄露)
        2. 1.1.0.3.1.2. 2. 样式冲突
        3. 1.1.0.3.1.3. 3. 难以维护
      2. 1.1.0.3.2. 为什么 scoped 无法影响 Element UI 组件
      3. 1.1.0.3.3. 问题原因
      4. 1.1.0.3.4. 解决方案:使用深度选择器
      5. 1.1.0.3.5. Vue 2 中的写法
        1. 1.1.0.3.5.1. 方法一:使用 >>>(Sass 中不适用)
        2. 1.1.0.3.5.2. 方法二:使用 /deep/
        3. 1.1.0.3.5.3. 方法三:使用 ::v-deep(推荐)
        4. 1.1.0.3.5.4. Vue 3 中的写法
      6. 1.1.0.3.6. <p> 标签(段落)
      7. 1.1.0.3.7. <span> 标签(内联)
      8. 1.1.0.3.8. 显示特性区别
        1. 1.1.0.3.8.1. <p> 标签
        2. 1.1.0.3.8.2. <span> 标签
      9. 1.1.0.3.9. 视觉对比
      10. 1.1.0.3.10. 在代码中的应用
      11. 1.1.0.3.11. 嵌套规则
        1. 1.1.0.3.11.1. 允许的嵌套:
        2. 1.1.0.3.11.2. 不允许的嵌套:
      12. 1.1.0.3.12. element样式不生效问题