实习日记
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 分为两个部分:body和footer,footer需要具名为footer的slot。title属性用于定义标题,它是可选的,默认值为空。最后,本例还展示了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)
|
1 2 3
| const a = document.createElement('a') a.href = url a.download = data.name
|
- 功能: 创建隐藏的
<a> 标签并设置下载属性
createElement('a'): 创建链接元素
href: 设置文件URL
download: 设置下载后的文件名
- 功能: 程序化触发链接点击,开始下载
- 用户无需手动点击,代码自动触发下载
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