一、概述
1.1介绍
Element Plus 基本使用
element-ui 是基于vue 开发的一套ui组件库,提供丰富的网页开发组件,可用快速开发网站,降低前端开发成本
版本 element目前有两个版本
- element-ui:基于vue2
- element-plus: 基于vue3
官网地址
https://element-plus.org/zh-CN/
element-plus 基本使用
1.安装 npm install element-plus 2. 在vue项目main.js引入element-plus组件,以及css文件 3. 在官方文档中找到需要的样式组件复制代码对应的.vue中使用。
具体部署请看快速开始
1.2网页基础布局
icon组件
安装
pnpm install @element-plus/icons-vue
在main.ts中进行全局挂载
官网图标地址
https://element-plus.org/zh-CN/component/icon.html#
Container 布局容器
<div class="common-layout">
<el-container>
<el-aside width="200px">Aside</el-aside>
<el-main>Main</el-main>
</el-container>
</div>
我们将这个布局抽离为两个组件,分别为一个header组件和一个aside组件,接下来开始抽离。
模板组件分离
header组件
<!-- eslint-disable @typescript-eslint/no-unused-vars -->
<!-- eslint-disable @typescript-eslint/no-unused-vars -->
<template>
<div>
<el-header style="display: flex; font-size: 16px;">
<!-- 左侧部分,包含侧边栏展开/折叠图标 -->
<div style="display: inline-flex; flex: 1; align-items: center; justify-content: left;">
<!-- 展开图标(非折叠状态时显示) -->
<el-icon v-show="!showIcon.isCollapse" @click="collapseAside" style="color: #303133;">
<Fold />
</el-icon>
<!-- 折叠图标(折叠状态时显示) -->
<el-icon v-show="showIcon.isCollapse" @click="collapseAside" style="color: #303133;">
<Expand />
</el-icon>
</div>
<!-- 右侧工具栏区域 -->
<div class="toolbar">
<!-- 用户头像 -->
<div class="block" style="margin-right: 10px;">
<el-avatar :size="40" :src="Avatar" />
</div>
<!-- 用户名文本 -->
<span>管理员</span>
<!-- 下拉菜单,包含更多操作选项 -->
<el-dropdown trigger="click">
<!-- 设置图标 -->
<el-icon style="margin-left: 18px; margin-top: 1px; color: #303133;">
<setting />
</el-icon>
<!-- 下拉菜单内容模板 -->
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>View</el-dropdown-item>
<el-dropdown-item>Add</el-dropdown-item>
<el-dropdown-item @click="LogOut">退出登录</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</el-header>
</div>
</template>
<script setup lang="ts">
import Avatar from '@/assets/touxiang.jpg'
import { ref } from 'vue'
// eslint-disable-next-line vue/no-dupe-keys, @typescript-eslint/no-unused-vars
const isCollapse = ref(true)
// 获取父组件传递过来的数据
const showIcon = defineProps({
isCollapse: Boolean
})
// 获取父组件自定义的事件
const emit = defineEmits(['changeAside'])
// 自定义按钮点击事件,侧边栏的收缩按钮
const collapseAside = () => {
emit('changeAside')
}
// 登出按钮
const LogOut = ()=>{
}
</script>
<style>
.el-header {
width: 100%;
background-color: #fff;
color: var(--el-text-color-primary);
box-shadow: var(--el-box-shadow);
}
.toolbar {
display: inline-flex;
align-items: center;
justify-content: center;
height: 100%;
right: 20px;
text-align: right;
}
.el-dropdown-menu__item {
width: 120px;
}
.icon-color {
color: white;
}
</style>
aside组件
<script setup>
import { Monitor } from '@element-plus/icons-vue';
import { ref } from 'vue'
const settings = defineProps({
collapse: Boolean,
width: String
})
const iconColor = ref('color:#F8FAFB')
</script>
<template>
<el-aside :width="settings.width">
<el-scrollbar>
<el-menu :default-openeds="['1', '3']"
:collapse="settings.collapse" active-text-color="#ffd04b"
background-color="#304156" text-color="#FFFFFF" router="true">
<el-menu-item index="1">
<el-icon><Monitor /></el-icon>
<template #title>仪表板</template>
</el-menu-item>
<el-sub-menu index="2">
<template #title>
<el-icon>
<Menu />
</el-icon><span>文章管理</span>
</template>
<el-menu-item index="/admin/articles">文章管理列表</el-menu-item>
</el-sub-menu>
<el-sub-menu index="3">
<template #title>
<el-icon>
<Message />
</el-icon><span>评论管理</span>
</template>
<el-menu-item index="/admin/comments">评论管理列表</el-menu-item>
</el-sub-menu>
<el-sub-menu index="4">
<template #title>
<el-icon>
<Files />
</el-icon><span>模块管理</span>
</template>
<el-menu-item index="/admin/blocks">模块管理列表</el-menu-item>
</el-sub-menu>
</el-menu>
</el-scrollbar>
</el-aside>
</template>
<style scoped>
.el-aside {
height: 100vh;
overflow: hidden;
box-shadow: var(--el-box-shadow-lighter);
}
.el-scrollbar {
height: 100vh;
overflow: hidden;
background-color: #304156;
}
.el-menu {
border-right: none;
}</style>
动态路由
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '@/views/HomeView.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: '仪表盘',
component: HomeView
},
{
path: '/article',
name: '文章管理',
component: HomeView,
children: [
{
path: '/id',
name: '文章管理列表',
component: () => (
'../views/A.vue'
)
}
]
},
{
path: '/comment',
name: '评论管理',
component: HomeView,
children: [
{
path: '/id',
name: '评论管理列表',
component: () => (
'../views/B.vue'
)
}
],
},
]
})
export default router
侧边栏代码改进
<template>
<el-aside :width="settings.width">
<el-scrollbar>
<el-menu :default-openeds="['1', '3']"
:collapse="settings.collapse" active-text-color="#ffd04b"
background-color="#304156" text-color="#FFFFFF" router="true">
<template v-for="menu in this.$router.options.routes" :key="menu">
<!-- 当前菜单项没有子菜单时 -->
<el-menu-item v-if="!menu.children" :index="menu.path">
<el-icon><component :is="menu.icon" ></component> </el-icon>
<span>{{menu.name}}</span>
</el-menu-item>
<!-- 当前菜单项有子菜单时 -->
<el-sub-menu v-else-if="menu.children" :index="menu.path">
<template #title>
<el-icon><component :is="menu.icon" ></component> </el-icon>
<span>{{menu.name}}</span>
</template>
<!-- 循环遍历子菜单项 -->
<el-menu-item v-for="child in menu.children" :key="child" :index="child.path">{{child.name}}</el-menu-item>
</el-sub-menu>
</template>
- Element Plus Icon组件:如果你正在使用 Element Plus UI 库,你可以直接使用其提供的 Icon 组件来显示图标。你可以在路由配置中使用该组件作为路由菜单的一部分,例如在
meta
字段中定义图标名称,然后在导航菜单的组件中动态渲染它。- SVG图标:你可以使用 SVG 格式的图标,并在你的 Vue 组件中直接引入它们。这种方法允许你在路由配置中指定不同的 SVG 文件,并在导航菜单中显示它们。
- @iconify/vue:这是一个流行的图标库,提供了多种图标集的支持。你可以通过这个库来在你的 Vue 项目中使用图标,包括在路由中。你可以选择适合你项目的图标集,并在路由配置中指定相应的图标类名。
整合
<script setup>
import { ref } from 'vue'
// 组件注册
import Header from '@/components/Header.vue'
import Aside from '@/components/Aside.vue'
const asideSettings = ref({
isCollapse:true,
width:'200'
})
// 给子组件绑定事件,通过子组件emit从而改变父组件的值
const changeAside = ()=>{
asideSettings.value.isCollapse = !asideSettings.value.isCollapse
if(asideSettings.value.isCollapse){
asideSettings.value.width = "64"
}else{
asideSettings.value.width = "200"
}
}
</script>
<template>
<el-container style="min-height: 100vh;min-width: 100vw;overflow: hidden;">
<Aside :collapse="asideSettings.isCollapse" :width="asideSettings.width"></Aside>
<el-container style="height: 100vh;width:100%;display: flex;flex-direction: column;">
<Header :isCollapse="asideSettings.isCollapse" @changeAside="changeAside"></Header>
<el-main>
<div v-if="$route.path === '/'">
<el-card>
<h1>文本内容</h1>
</el-card>
</div>
<router-view v-else></router-view>
</el-main>
</el-container>
</el-container>
</template>
<style scoped>
body{
background-color: #eee;
max-width: 100vw;
overflow: hidden;
}
.el-main {
width: 100%;
padding: 0;
height: 100vh;
overflow-x: hidden;
}
</style>
1.3基础布局知识
盒子模型拆分网页
在你的 UserController 的上面加个小注解
@CrossOrigin
`@CrossOrigin` 注解是 Java 中 Spring 框架提供的一种用于处理跨域请求的方法。跨域请求通常出现在前后端分离的 Web 应用中,当前端和后端部署在不同的域名或端口下时,浏览器会因为同源策略(Same-origin policy)而阻止跨域请求。
使用 `@CrossOrigin` 注解可以允许来自不同域的请求访问后端资源。该注解可以应用于类级别和方法级别,用于配置 CORS(CORS:跨域资源共享)相关的参数。
下面是一个示例代码,演示如何在 Spring 中使用 `@CrossOrigin` 注解:
import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController @CrossOrigin(origins = "http://example.com", maxAge = 3600) public class MyController { @GetMapping("/api/data") @CrossOrigin(methods = ["GET"], allowedHeaders = ["Content-Type"]) public String getData() { // 处理跨域请求的逻辑 return "Hello, World!"; } }
在上述代码中,`@CrossOrigin` 注解应用于类级别和方法级别。类级别的注解允许来自 `http://example.com` 域的请求访问所有方法。方法级别的注解进一步限制了只允许 `GET` 方法的跨域请求,并指定了允许的请求头为 `Content-Type`。
通过配置 `@CrossOrigin` 注解,可以实现对跨域请求的灵活控制,确保安全性和数据的正确交互。
二、Element Plus 基本样式
2.1按钮
<template>
<h3>按钮</h3>
<el-button>默认按钮</el-button>
<el-button type="primary">主要按钮</el-button>
<el-button type="success">成功按钮</el-button>
<el-button type="info">信息按钮</el-button>
<el-button type="warning">警告按钮</el-button>
<el-button type="danger">危险按钮</el-button>
<hr>
<h3>按钮属性</h3>
<el-button plain>朴素按钮</el-button>
<el-button round>圆角按钮</el-button>
<el-button circle>圆</el-button>
<el-button disabled>禁用按钮</el-button>
<el-button loading>加载中</el-button>
<hr>
<h3>尺寸</h3>
<el-button size="large">大型按钮</el-button>
<el-button>默认按钮</el-button>
<el-button size="small">小型按钮</el-button>
</template>
2.2图标
<template>
<h3>图标</h3>
<el-icon><Plus /></el-icon>
<el-icon><Edit /></el-icon>
<el-icon><Delete /></el-icon>
<el-icon class="is-loading"><Loading /></el-icon>
<hr>
<h3>属性</h3>
<el-icon size="30" color="red"><Search /></el-icon>
<hr>
<h3>按钮</h3>
<el-button type="primary">
<el-icon><Search /></el-icon>
<span> 搜索 </span>
</el-button>
<el-button type="primary">
<el-icon><Search /></el-icon>
</el-button>
<el-button type="primary" circle>
<el-icon><Search /></el-icon>
</el-button>
<hr>
<h3>按钮组</h3>
<el-button-group>
<el-button type="primary">
<el-icon><Plus /></el-icon>
</el-button>
<el-button type="primary">
<el-icon><Edit /></el-icon>
</el-button>
<el-button type="primary">
<el-icon><Delete /></el-icon>
</el-button>
</el-button-group>
</template>
2.3提示框
<script setup lang="ts">
import { ElMessage, ElMessageBox, ElNotification } from 'element-plus'
// 消息
const openMsg = () => {
ElMessage({
type: 'success', // success | warning | info | error
message: 'hello world',
showClose: true
})
}
// 确认框
const openConfirm = () => {
ElMessageBox.confirm('确认删除?', '标题', {
type: 'warning',
confirmButtonText: '确认',
cancelButtonText: '取消'
}).then(() => {
console.log('确认')
}).catch(() => {
console.log('取消')
})
}
// 通知
const openNotifiy = () => {
ElNotification({
title: '标题',
message: '烟雨平生',
duration: 1500 // 展示时间 [单位:毫秒]
})
}
// 通知2
const openNotifiy2 = () => {
ElNotification({
type: 'success', // success | warning | info | error
title: '标题',
message: 'hello world',
duration: 1500,
position: 'bottom-right'
})
}
</script>
<template>
<div>
<el-button @click="openMsg">消息</el-button>
<el-button @click="openConfirm">确认框</el-button>
<el-button @click="openNotifiy">通知</el-button>
<el-button @click="openNotifiy2">通知2</el-button>
</div>
</template>
2.4导航
详情请见导航
2.5标签页
<script setup lang="ts">
import { ref, reactive } from 'vue'
//默认选中的标签名称
const selectedName = ref("2")
//选中标签触发的回调
const tabClick = (tab, event) => {
console.log("tab", tab.props, "event", event)
}
const tab = reactive({
arr: [
{ name: "1", title: '烟雨', content: '内容1' },
{ name: "2", title: '烟雨平生', content: '内容2' },
{ name: "3", title: 'com', content: '内容3' },
]
})
//添加
const tabAdd = () => {
let index = tab.arr.length
index++
tab.arr.push({
name: index,
title: '新选项卡' + index,
content: '内容' + index
})
}
//移除
const tabRemove = (name) => {
console.log("name:", name)
const index = tab.arr.findIndex((value) => {
return value.name === name
})
tab.arr.splice(index, 1) //移除元素
}
</script>
<template>
<div>
<h3>标签页</h3>
<el-tabs v-model="selectedName" @tab-click="tabClick">
<el-tab-pane label="烟雨" name="1">内容1</el-tab-pane>
<el-tab-pane label="烟雨平生" name="2">内容2</el-tab-pane>
<el-tab-pane label="com" name="3">内容3</el-tab-pane>
</el-tabs>
<h3>卡片风格</h3>
<el-tabs v-model="selectedName" @tab-click="tabClick" type="card">
<el-tab-pane label="烟雨" name="a">内容1</el-tab-pane>
<el-tab-pane label="烟雨平生" name="b">内容2</el-tab-pane>
<el-tab-pane label="com" name="c">内容3</el-tab-pane>
</el-tabs>
<h3>带有边框的卡片风格</h3>
<el-tabs v-model="selectedName" @tab-click="tabClick" type="border-card">
<el-tab-pane label="烟雨" name="A">内容1</el-tab-pane>
<el-tab-pane label="烟雨平生" name="B">内容2</el-tab-pane>
<el-tab-pane label="com" name="C">内容3</el-tab-pane>
</el-tabs>
<h3>动态添加</h3>
<el-button @click="tabAdd">添加</el-button>
<el-tabs v-model="selectedName" @tab-remove="tabRemove" closable type="card">
<el-tab-pane v-for="(value, key) in tab.arr" :key="value.name" :label="value.title" :name="value.name">
{{ value.content }}
</el-tab-pane>
</el-tabs>
</div>
</template>
2.6输入框
详情请见输入框
<script setup lang="ts">
import { ref } from 'vue'
const name = ref('')
const password = ref('')
const content = ref('烟雨平生')
const url = ref('com')
const url2 = ref('code')
const email = ref('123456')
//const selected = ref('')
const selected = ref('2') //选中的下拉框
</script>
<template>
<div style="width: 300px;">
<!-- clearable 可一键清空 -->
<h3>输入框</h3>
<el-input v-model="name" clearable placeholder="请输入用户名" />
<!-- show-password 可切换显示隐藏密码 -->
<h3>密码框</h3>
<el-input v-model="password" show-password placeholder="请输入密码" />
<h3>文本域</h3>
<el-input type="textarea" v-model="content" rows="2" />
<h3>输入内容长度限制 - 输入框</h3>
<el-input v-model="name" maxlength="10" show-word-limit />
<h3>输入内容长度限制 - 文本域</h3>
<el-input type="textarea" v-model="content" maxlength="20" rows="3" show-word-limit />
<h3>尺寸</h3>
大 <el-input size="large" />
默认 <el-input />
小 <el-input size="small" />
<h3>前置</h3>
<el-input v-model="url">
<template #prepend>https://</template>
</el-input>
<h3>后置</h3>
<el-input v-model="email">
<template #append>@qq.com</template>
</el-input>
<h3>前置后置</h3>
<el-input v-model="url2">
<template #prepend>https://</template>
<template #append>.com</template>
</el-input>
<h3>前置后置扩展 - 搜索</h3>
<el-input placeholder="请输入课程名称">
<template #prepend>
<el-select v-model="selected" placeholder="请选择" style="width: 100px;">
<el-option label="前端" value="1" />
<el-option label="后端" value="2" />
<el-option label="服务端" value="3" />
</el-select>
</template>
<template #append>
<el-button>
<el-icon><Search /></el-icon>
</el-button>
</template>
</el-input>
</div>
</template>
2.7单选框、复选框
详情请见单选框
2.8下拉框
<script setup lang="ts">
import { ref,reactive } from 'vue'
const selected = ref('2')
const selected2 = ref('')
const selected3 = ref('C')
const selected4 = ref(['1','3'])
const data = reactive({
options: [
{ value: 'A', label: '前端', },
{ value: 'B', label: '后端', },
{ value: 'C', label: '服务端', }
]
})
//回调
const selectChange = (val) => {
console.log("selectChange:", val)
}
</script>
<template>
<div style="width: 300px;">
<h3>下拉框</h3>
<el-select v-model="selected" placeholder="请选择">
<el-option value="1" label="前端" />
<el-option value="2" label="后端" />
<el-option value="3" label="服务端" />
</el-select>
<h3>下拉框 - 事件绑定</h3>
<el-select v-model="selected2" @change="selectChange" placeholder="请选择">
<el-option value="a" label="前端" />
<el-option value="b" label="后端" />
<el-option value="c" label="服务端" />
</el-select>
<h3>动态下拉框</h3>
<el-select v-model="selected3" placeholder="请选择">
<el-option v-for="item in data.options"
:value="item.value"
:label="item.label"
:key="item.value" />
</el-select>
<h3>多选 - multiple</h3>
<el-select v-model="selected4" multiple @change="selectChange" placeholder="请选择">
<el-option value="1" label="前端" />
<el-option value="2" label="后端" />
<el-option value="3" label="服务端" />
</el-select>
</div>
</template>
2.9日期选择器
详情请见日期选择器
2.10表单
2.11对话框
详情请见对话框
<script setup>
import { ref } from 'vue'
const data = ref({
name: '',
radio: '',
checkbox: [],
date: '',
select: '',
multipleSelect: [],
textarea: ''
})
const add = () => {
console.log(data.value)
}
const reset = () => {
data.value = {
name: '',
radio: '',
checkbox: [],
date: '',
select: '',
multipleSelect: [],
textarea: ''
}
}
//对话框
const dialog = ref(false)
const dialogClose = () => {
console.log("关闭")
}
</script>
<template>
<el-button @click="dialog = true">打开</el-button>
<!-- draggable 允许拖拽 -->
<el-dialog v-model="dialog" width="500" title="标题" draggable @close="dialogClose">
<el-form label-width="80">
<el-form-item label="文本框">
<el-input v-model="data.name" placeholder="请填写名称" />
</el-form-item>
<el-form-item label="单选框">
<el-radio-group v-model="data.radio">
<el-radio value="1">前端</el-radio>
<el-radio value="2">后端</el-radio>
<el-radio value="3">服务端</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="复选框">
<el-checkbox-group v-model="data.checkbox">
<el-checkbox value="a">前端</el-checkbox>
<el-checkbox value="b">后端</el-checkbox>
<el-checkbox value="c">服务端</el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item label="日期时间">
<el-date-picker v-model="data.date" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" />
</el-form-item>
<el-form-item label="下拉框">
<el-select v-model="data.select" placeholder="请选择">
<el-option value="A" label="前端" />
<el-option value="B" label="后端" />
<el-option value="C" label="服务端" />
</el-select>
</el-form-item>
<el-form-item label="多选框">
<el-select v-model="data.multipleSelect" multiple placeholder="请选择">
<el-option value="AA" label="前端" />
<el-option value="BB" label="后端" />
<el-option value="CC" label="服务端" />
</el-select>
</el-form-item>
<el-form-item label="文本域">
<el-input type="textarea" v-model="data.textarea" rows="2" placeholder="请填写内容" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="add">添加</el-button>
<el-button @click="reset">重置</el-button>
</el-form-item>
</el-form>
</el-dialog>
</template>
2.12表格
详情请见表格
三、实战进阶
3.1设置布局
栅格布局:通过基础的24分栏,迅速便捷创建布局,
el-row 代表行,里面嵌套el-col
el-col 代表列,总分为24列
属性
gutter列间隔
span占据的列数
<script setup>
import { ref } from 'vue'
</script>
<template>
<div>
<h3>这是A页面的栅格</h3>
<el-row :gutter="10">
<el-col :span="12">
<div style="background: green">第一列</div>
</el-col>
<el-col :span="12">
<div style="background: orange">第二列</div>
</el-col>
</el-row>
<br>
<el-row :gutter="10">
<el-col :span="8">
<div style="background: green">第一列</div>
</el-col>
<el-col :span="8">
<div style="background: orange">第二列</div>
</el-col>
<el-col :span="8">
<div style="background: blueviolet">第三列</div>
</el-col>
</el-row>
<br>
<el-row :gutter="10">
<el-col :span="4">
<div style="background: green">第一列</div>
</el-col>
<el-col :span="5">
<div style="background: orange">第二列</div>
</el-col>
<el-col :span="8">
<div style="background: blueviolet">第三列</div>
</el-col>
</el-row>
</div>
</template>
<style scoped></style>
3.2表单:校验规则
表单包含输入框,单选框,下拉选择,多选框等用户输入的组件。使用表单可以收集,验证和提交数据。
表单项常用组件:
el-input: 输入框
el-select: 下拉框
el-checkbox-group 多选框
el-radio-group:单选框
表单:校验规则
表单组件允许你校验用户的宿儒是否符合规范,来帮助你找到和纠正错误
使用流程
1.定义校验规则
2el-form指定“rules” 属性传入定义的校验规则
3.el-form-item指定“prop”属性与校验规则名称对应
<script setup lang="ts">
import { reactive ,ref} from 'vue';
import { ElForm, FormInstance , FormRules} from 'element-plus';
// 导入 ElForm 组件的实例类型
interface FormModel {
name: string;
age: string;
sex: string;
}
const form = reactive<FormModel>({
name: 'BO',
age: '',
sex: ''
});
const formRules = {
name: [
{ required: true, message: '请输入姓名', trigger: 'blur' },
{ min: 2, max: 5, message: '长度在 3 到 5 个字符', trigger: 'blur' }
],
age: [
{ required: true, message: '请输入年龄', trigger: 'blur' }
],
sex: [
{ required: true, message: '请选择性别', trigger: 'change' }
]
};
const formRef = ref<FormInstance>()
// 定义表单引用并赋予正确类型
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
}
const submitForm = async (formEl: FormInstance | undefined) => {
if (!formEl) return
await formEl.validate((valid, fields) => {
if (valid) {
console.log('submit!')
console.log(form)
formEl.resetFields()
} else {
console.log('error submit!', fields)
}
})
}
</script>
<template>
<div>
<H3>这是B界面</H3>
<el-form :model="form" :rules = "formRules" ref ="formRef">
<el-form-item label="姓名" prop="name">
<el-input v-model="form.name" />
</el-form-item>
<el-form-item label="年龄" prop="age">
<el-input v-model="form.age"/>
</el-form-item>
<el-form-item label="性别" prop="sex">
<el-select v-model="form.sex" placeholder="请选择性别">
<el-option label="男" value="男" />
<el-option label="女" value="女" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm(formRef)">提交</el-button>
<el-button @click="resetForm(formRef)">重置</el-button>
</el-form-item>
</el-form>
</div>
</template>
3.3表格
边框,宽度,固定列
表格属性:
border:是否带有纵向边框
data:表格使用的数据,自动渲染
列属性:
prop: 键名,对应数据中的字段
label:列名
width:列宽度
fixed:列是否固定在左侧或者右侧, true 表示固定在左侧
fixed= "right"
卡片
悬浮展示数据,类似于卡片效果。
详情请见卡片
<script setup lang="ts">
import { ref, reactive } from 'vue';
const tableData = [
{
date: '2016-05-03',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-02',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-04',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-01',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
]
</script>
<template>
<div>
<el-card class="box-card">
<template #header>
<div class="card-header">
<span>用户列表</span>
</div>
</template>
<el-button type="primary">新增数据</el-button>
<div style="margin:0 10px">
<el-table :data="tableData" style="width: 100%">
<el-table-column prop="date" label="日期" width="180" align = 'center' />
<el-table-column prop="name" label="姓名" width="180" align = 'center'/>
<el-table-column prop="address" label="地址" align = 'center'/>
</el-table>
</div>
</el-card>
</div>
</template>
弹窗
<script setup lang="ts">
import { computed, ref, reactive, watch } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus'
const dialogFormVisible = ref(false)
const GlobalIndex = ref(-1)
const name = ref('')
interface User {
name: string;
city: string;
age: number;
}
const tableData = reactive<Array<User>>([
{
date: '2016-05-03',
name: 'Tom1',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-02',
name: 'Tom2',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-04',
name: 'Tom3',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-01',
name: 'Tom4',
address: 'No. 189, Grove St, Los Angeles',
},
])
const now = reactive(new Date());
let form = reactive({
date: now.toISOString().substring(0, 10),
name: '',
address: '',
})
const handeAdd = () => {
form = reactive({
date: now.toISOString().substring(0, 10),
name: '',
address: '',
})
dialogFormVisible.value = true
}
const save = () => {
if(GlobalIndex.value >=0){
console.log(GlobalIndex.value)
tableData[GlobalIndex.value] = form
GlobalIndex.value = -1
}
else{
tableData.push(form)
}
dialogFormVisible.value = false
}
const handleEdit = (row,index) => {
const newobj = Object.assign({}, row)
form = reactive(newobj)
GlobalIndex.value = index
dialogFormVisible.value = true
}
const handleDelete = (index: number) => {
ElMessageBox.confirm('是否删除该条数据?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
tableData.splice(index, 1); // 删除指定索引的数据
ElMessage({
type: 'success',
message: '删除成功!'
});
}).catch(() => {
ElMessage({
type: 'info',
message: '已取消删除'
});
});
};
// 搜索关键字状态管理
const searchValue = ref('');
// 定义计算属性,根据搜索关键字过滤表格数据
const filterTableData = computed(() =>
tableData.filter(
(data) =>
!searchValue.value ||
data.name.toLowerCase().includes(searchValue.value.toLowerCase())
)
);
// 监听 searchValue 的变化
watch(searchValue, (newValue, oldValue) => {
if (!newValue) {
filterTableData.value = tableData;
}
});
// 搜索功能的实现
const search = () => {
searchValue.value = name.value;
console.log(searchValue.value); // 更新搜索关键字为输入框的值
};
</script>
<template>
<div>
<el-card class="box-card">
<template #header>
<div class="card-header">
<span>用户列表</span>
</div>
</template>
<!-- Element UI Input 组件,用于输入搜索名称 -->
<el-input style="width:300px" placeholder="请输入名称" v-model="name" clearable></el-input>
<!-- Element UI 主题样式按钮,点击后执行搜索动作 -->
<el-button type="primary" @click="search" style="margin-left:5px">搜索</el-button>
<el-button type="primary" @click="handeAdd" >新增数据</el-button>
<div style="margin:0 10px">
<el-table :data="filterTableData" style="width: 100%">
<el-table-column prop="date" label="日期" sortable width="180" align = 'center' />
<el-table-column prop="name" label="姓名" width="180" align = 'center'/>
<el-table-column prop="address" label="地址" align = 'center'/>
<el-table-column align = 'right'>
<template #default="scope">
<el-button link type="primary" size="small" @click="handleEdit(scope.row,scope.$index)"
>编辑</el-button>
<el-button link type="danger" size="small" @click.prevent="handleDelete(scope.$index)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<el-dialog v-model="dialogFormVisible" title="信息" width="50%">
<el-form :model="form" label-width="100px" style="padding-right: 30px;" >
<el-form-item label="日期" >
<el-input v-model="form.date" autocomplete="off" />
</el-form-item>
<el-form-item label="姓名" >
<el-input v-model="form.name" autocomplete="off" />
</el-form-item>
<el-form-item label="地址" >
<el-input v-model="form.address" autocomplete="off" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="dialogFormVisible = false">取消</el-button>
<el-button type="primary" @click="save">
确认
</el-button>
</div>
</template>
</el-dialog>
</el-card>
</div>
</template>
分页·
详情请看分页
const total = ref(10)
const pageNum = ref(1)
const pageSize = ref(1)
<div style = "margin: 15px 0">
<el-pagination background layout="sizes, prev, pager, next"
v-model:current-page="pageNum"
v-model:page-size="pageSize"
:page-sizes="[1, 5,10]"
:total="total"
@size-change="load"
@current-change="load"/>
</div>
国际化
import ElementPlus from 'element-plus'
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
app.use(ElementPlus, {
locale: zhCn,
})
日期选择器
详情请见日期选择器
<el-date-picker
v-model="value2"
type="date"
placeholder="Pick a day"
:disabled-date="disabledDate"
:shortcuts="shortcuts"
:size="size"
/>
3.4轮播图
<script setup lang="ts">
import img1 from '@/assets/lunbo1.png';
import img2 from '@/assets/lunbo2.png';
import img3 from '@/assets/lunbo3.png';
import img4 from '@/assets/lunbo4.png';
const carouselData = [
{ url: img1 },
{ url: img2 },
{ url: img3 },
{ url: img4 },
]
</script>
<template>
<div>
<el-carousel :interval="4000" type="card" height="300px">
<el-carousel-item v-for="item in carouselData" :key="item.url">
<img :src="item.url" alt="轮播图片" style="width: 100%; height: 200px;"/>
<h3>{{ item.url }}</h3>
</el-carousel-item>
</el-carousel>
</div>
</template>
<style>
.el-carousel__item h3 {
color: #475669;
opacity: 0.75;
line-height: 200px;
margin: 0;
text-align: center;
}
.el-carousel__item:nth-child(2n) {
background-color: #99a9bf;
}
.el-carousel__item:nth-child(2n + 1) {
background-color: #d3dce6;
}
</style>
3.5面包屑
详请参考https://juejin.cn/post/7087003440773070856
路由
<template>
<div class="breadcrumb">
<!-- 使用 element-plus 的面包屑组件 -->
<el-breadcrumb separator="/">
<!-- 循环渲染面包屑导航项 -->
<el-breadcrumb-item v-for="(crumb, index) in breadcrumbs" :key="index">
<!-- 使用路由链接包装每个面包屑导航项 -->
<router-link :to="crumb.to">{{ crumb.title }}</router-link>
</el-breadcrumb-item>
</el-breadcrumb>
</div>
</template>
<script setup lang="ts">
// 导入所需的模块
import { computed } from 'vue';
import { useRouter } from 'vue-router';
// 获取当前路由实例
const router = useRouter();
// 使用 computed 函数计算面包屑导航项
const breadcrumbs = computed(() => {
// 从当前路由匹配的规则中筛选出带有 isBreadcrumb 元信息的规则
const matchedRoutes = router.currentRoute.value.matched.filter(route => route.meta && route.meta.isBreadcrumb);
// 根据匹配到的路由规则生成面包屑导航项
return matchedRoutes.map(route => ({
to: route.path, // 面包屑导航项的链接路径
title: route.meta.title, // 面包屑导航项的标题
}));
});
</script>
<style scoped>
.breadcrumb {
display: inline-flex;
align-items: center;
justify-content: flex-start;
text-align: right;
margin: 0 20px;
flex: 1;
}
</style>