文章目录
element系列插件用途广泛。
安装并引入
通用组件推荐在main.js引入,以下内容添加到main.js文件中:
js
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
const app = createApp(App)
app.use(ElementPlus) // 注册插件
el-dialog组件
弹框插件,将常用的功能,如标题,点击事件作为属性,避免了重复写代码。
el-dialog属性列表
el-dialog新增示例-html部分
html
<el-dialog v-model="showAddDialog" title="新增项目资料" width="500px" :close-on-click-modal="false">
<el-form :model="newResourceForm" label-width="80px">
<el-form-item label="资料名称">
<el-input v-model="newResourceForm.resourceName" placeholder="请输入资料名称" />
</el-form-item>
<el-form-item label="上传文件">
<el-upload
:action="uploadUrl"
:on-success="handleUploadSuccess"
:limit="1"
accept=".pdf,.zip,.rar,.doc,.docx">
<el-button type="primary">点击上传</el-button>
<template #tip>
<div class="el-upload__tip">支持 pdf/zip/doc 等格式</div>
</template>
</el-upload>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="showAddDialog = false">取消</el-button>
<el-button type="primary" :loading="submitting" @click="handleSubmit">保存</el-button>
</template>
</el-dialog>
el-dialog新增示例-js部分
js
// 表单数据
const newResourceForm = ref({
resourceName: '',
resourcePath: '' // 上传成功后由接口返回
});
// 1. 处理文件上传成功
const handleUploadSuccess = (response) => {
if (response.success && response.data && response.data.length > 0) {
// 你的接口返回的 data 是一个数组,取第一个作为路径
newResourceForm.value.resourcePath = response.data[0];
ElMessage.success('文件上传成功');
} else {
ElMessage.error(response.message || '文件上传失败');
}
};
// 2. 提交保存
const handleSubmit = async () => {
if (!newResourceForm.value.resourceName || !newResourceForm.value.resourcePath) {
ElMessage.warning('请填写资料名称并上传文件');
return;
}
submitting.value = true;
try {
const response = await fetch('/mysite/api/projectResource/insert', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
projectId: projectId,
resourceName: newResourceForm.value.resourceName,
resourcePath: newResourceForm.value.resourcePath
})
});
const result = await response.json();
if (result.success) {
ElMessage.success('新增资料成功');
showAddDialog.value = false;
// 核心:保存成功后,重新拉取项目详情,刷新列表
fetchProjectDetail();
} else {
ElMessage.error(result.message || '保存失败');
}
} catch (err) {
ElMessage.error('网络请求失败');
} finally {
submitting.value = false;
}
};
el-upload
el-upload属性列表
:action
:action 用于指定文件上传的后台接口地址(url)
示例
python
<el-upload
:action="uploadUrl" //
:on-success="handleUploadSuccess"
:limit="1"
accept=".pdf,.zip,.rar,.doc,.docx">
<el-button type="primary">点击上传</el-button>
<template #tip>
<div class="el-upload__tip">支持 pdf/zip/doc 等格式</div>
</template>
</el-upload>
解读:
:action="uploadUrl" # 绑定上传地址
:on-success="handleUploadSuccess" # 成功后回调函数
:limit="1" # 限制允许上传的文件最大数量为1个
accept=".pdf,.zip,.rar,.doc,.docx" # 允许的文件类型
<el-button type="primary">点击上传</el-button>
type="primary" #
按钮类型
除了 primary,Element 还提供了其他几种内置类型,用于区分不同的操作场景:
默认(不写 type):用于一般性操作(如:取消、返回)。
type="primary":常规按钮(蓝色)。
type="success":成功按钮(绿色),用于正向操作(如:通过、发布)。
type="warning":警告按钮(橙色/黄色),用于需要谨慎的操作。
type="danger":危险按钮(红色),用于破坏性操作(如:删除、清空)。
type="info":信息按钮(灰色),用于中性信息展示。
上传弹框更换图片的原理?
这块开始没看懂,其实很简单。
点更换图片相当于触发文件选择控件,选完文件后触发回调函数,这个函数里面主要做如下逻辑:
1、请求上传接口,解析返回报文
2、将表单该字段赋值为文件地址,如:
js
直接赋值:
form.value.coverUrl = result.data[0];
拼接地址的赋值:
form.value.coverUrl = PREVIEW_BASE + result.data[0];
const fileInputRef = ref(null); // 用于触发文件选择框
html
<div class="upload-actions">
<input
type="file"
ref="fileInputRef"
@change="handleUpload"
accept="image/*"
style="display: none"
/>
<button
type="button"
@click="$refs.fileInputRef.click()"
:disabled="loading"
class="upload-btn"
>
{{ form.coverUrl ? "更换封面" : "上传封面" }}
</button>
<span v-if="uploading" class="upload-status">上传中...</span>
</div>
</div>
</div>
ElMessage
ElMessage是消息框,属于弹框的一种。
例如上传用对话框,成功后用消息框。
作用是简化了,消息框的使用,一行代码搞定。
js
import { ElMessage } from 'element-plus'
// 普通提示(灰色)
ElMessage('这是一条普通消息')
// 成功提示(绿色,带对勾图标)
ElMessage.success('操作成功!')
// 警告提示(黄色,带感叹号图标)
ElMessage.warning('请先选择文件')
// 错误提示(红色,带叉号图标)
ElMessage.error('网络异常,请稍后再试')
ref
最核心的机制之一。
示例
js
// 弹窗相关状态
const showAddDialog = ref(false);
const submitting = ref(false);
const uploadUrl = '/mysite/api/projectResource/upload'; // 你的上传接口地址
// 表单数据
const newResourceForm = ref({
resourceName: '',
resourcePath: '' // 上传成功后由接口返回
});
为什么要用ref,直接定义变量不行吗?
ref好。
1、可变 # vue setup中顶层声明的变量不可变
2、响应式 # 不使用ref,值变化不会告诉浏览器
vue的渲染过程
之前会有个疑问,vue中html先执行还是js先执行的呢?
举个例子就明白了。
1、vue内容
html
<div class="box">{{ message }}</div>
2、解析为抽象语法树
js
{
type: 'Element',
tag: 'div',
attrs: [{ name: 'class', value: 'box' }],
children: [
{
type: 'Interpolation', // 标记这是一个插值表达式
content: 'message'
}
]
}
3、输出渲染函数
js
function render(_ctx) {
// _ctx 代表组件的上下文(即你的 data 或 setup 返回的数据)
// h (或 _createVNode) 是 Vue 内部用来创建虚拟 DOM 的函数
return h('div', { class: 'box' }, _ctx.message);
}
这个渲染函数是如何工作的?
1、当Vue需要渲染页面时,它会执行这个render函数:
2、函数读取_ctx.message的值(比如"HelloVue")。
3、通过h()函数,在内存中生成一个轻量级的JavaScript对象,也就是虚拟DOM(VNode)。
4、Vue的运行时(Runtime)拿到这棵虚拟DOM树后,再调用浏览器原生的API(如document.createElement),将其映射为真实的DOM节点并插入到页面中。
动态绑定语法
:src示例
静态地址:
html
<img src="../../public/placeholder-image.jpg" alt="项目封面" class="cover-img" />
动态地址:
如果图片在/public目录下,不用加/public前缀,直接写文件名即可。
html
<img :src="'placeholder-image.jpg'" alt="项目封面" class="cover-img" />
:class示例
html
<button
class="tab-btn"
:class="{ active: activeTab === 'resources' }"
@click="activeTab = 'resources'"
>
:class # 这是动态绑定语法,作用是告诉vue,引号里面是js表达式,请计算结果并将结果作为css类名添加到元素上
active: # 类似于三目运算法符
activeTab # 这个是自定义的ref对象
整体的作用是:如果activeTab === 'resources',就给这个按钮添加active样式。
css为:
css
.tab-btn.active { background-color: #00b894; color: white; border-color: #00b894; }
注:这个并不是切换tab页的整体效果,只是tab页标签的颜色效果。
如何区分动态绑定语法和伪类?
它们长的很像。
1、在vue中是动态绑定语法
2、在style中是伪类
v-html
核心作用:
将一段包含HTML标签的字符串,直接解析并渲染为真实的DOM结构。
应用场景:
1、markdown页面解析 # 见vue markdown笔记
2、嵌入某个div块
v-html
html
<template>
<!-- 模板保持极简,只负责绑定 -->
<div class="container" v-html="staticHtml"></div>
</template>
<script setup>
import { computed } from 'vue';
// 在 computed 中定义好完整的 HTML 结构
const staticHtml = computed(() => {
return `
<div class="card">
<h3>这是标题</h3>
<p>这是一段描述内容,<strong>支持加粗</strong>。</p>
<ul>
<li>列表项 1</li>
<li>列表项 2</li>
</ul>
</div>
`;
});
</script>
指令
在vue中v-开头的表示指令。
v-if指令
v-if,v-else-if ,v-else
可以用来控制显隐,例如作为tab页的基础。
html
<div class="content-panel" v-if="activeTab === 'resources'"></div>
实现tab页效果
实现tab页效果-html-导航栏部分
html
<div class="resources-section" v-if="!loading && !error">
<!-- Tab 导航栏 -->
<div class="tabs">
<button
class="tab-btn"
:class="{ active: activeTab === 'resources' }"
@click="activeTab = 'resources'"
>
项目资料
</button>
<button
class="tab-btn"
:class="{ active: activeTab === 'intro' }"
@click="activeTab = 'intro'"
>
项目介绍
</button>
<button
class="tab-btn"
:class="{ active: activeTab === 'videos' }"
@click="activeTab = 'videos'"
>
视频目录
</button>
<button
class="tab-btn"
:class="{ active: activeTab === 'teacher' }"
@click="activeTab = 'teacher'"
>
讲师介绍
</button>
</div>
实现tab页效果-html-内容部分
html
<div class="content-panel" v-if="activeTab === 'resources'">项目资料内容</div>
<div class="content-panel" v-else-if="activeTab === 'videos'"></div>
<div class="content-panel" v-else-if="activeTab === 'intro'"></div>
<div class="content-panel" v-else-if="activeTab === 'teacher'"></div>
实现tab页效果-js部分
js
const activeTab = ref('resources'); // ✅ 新增:控制当前激活的 Tab,默认显示资料
实现下拉菜单
主要有这个几个标签:
:外层触发器容器,负责控制下拉行为的触发(如你代码中的 trigger="hover")。
:下拉浮层的内容区,必须嵌套在 内部。
:具体的菜单项条目,必须嵌套在 内部。
实现下拉菜单-html部分
html
<div class="nav-item dropdown-wrapper">
<el-dropdown trigger="hover">
<span class="el-dropdown-link nav-link-text">
积分专区
<!-- 小箭头图标 -->
<el-icon class="el-icon--right"><arrow-down /></el-icon>
</span>
<!-- 下拉的内容列表 -->
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item icon="CircleCheck">
<router-link to="/points/tasks" style="text-decoration: none; color: inherit;">
积分任务
</router-link>
</el-dropdown-item>
<el-dropdown-item icon="Document" divided>
<router-link to="/points/exchange" style="text-decoration: none; color: inherit;">
兑换免费资料
</router-link>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
实现下拉菜单-箭头-js部分
element-plus本来就带下拉菜单,引入方式见上文,属于通用方式。
这里用到了箭头,需要额外再引入下:
js
import { ArrowDown } from '@element-plus/icons-vue'
上文中的这部分用到了箭头:
html
<el-icon class="el-icon--right"><arrow-down /></el-icon>
实现下拉菜单(简版)(不带router-link)
html
<div class="nav-item dropdown-wrapper">
<el-dropdown trigger="hover">
<span class="el-dropdown-link nav-link-text">
主菜单
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item icon="CircleCheck">
子菜单1
</el-dropdown-item>
<el-dropdown-item icon="Document" divided>
子菜单2
</el-dropdown-item>
<el-dropdown-item icon="Document" divided>
子菜单3
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>