2. Vue 进阶
1) ElementUI
ElementUI是基于vue的一套组件库,前面讲述了如何自己去创建组件,但是自己创建组件成本太高了,所以我们一般都是采用一些第三方的比较成熟的组件库,ElementUI就是其中一中,使用之后可以大大减少我们的开发成本。
安装
代码语言:javascript复制 npm install element-ui -S
引入组件
引入的方式有很多种,这里就介绍个最简单的,引入所有的组件
放在main.js中
代码语言:javascript复制 import Element from 'element-ui' // 导入ElementUI组件
import 'element-ui/lib/theme-chalk/index.css' // 导入他的一些样式
// 之前我们自己使用组件的时候,我们是给options对象里的components去加组件
// 但是ElementUI里的组件太多了,个数大于有几十种,如果一个个去加,太麻烦了,
// 所以使用了另外一个手段vue的use方法,将Element对象传入,就会把所有Element的组件加入到内部去,以后在页面里就可以直接使用相关标签了
Vue.use(Element)
测试,在自己的组件中使用 ElementUI 的组 件
代码语言:javascript复制 <!-- ElementUI测试 -->
<template>
<div>
<el-button>点我</el-button>
</div>
</template>
<script>
export default {}
</script>
使用:
去ElementUI用啥找啥就行,参考官网的例子。
1. 表格组件
具体属性见:https://element.eleme.cn/#/zh-CN/component/table
代码语言:javascript复制 <template>
<div>
<!-- data属性:关联表格需要展示的数据 -->
<el-table v-bind:data="students">
<!-- lable属性:这个列的标题 -->
<!-- prop属性:表格内部会遍历这个学生数组,那么学生对象的哪个属性需要显示在这一列上就使用到了prop -->
<el-table-column label="编号" prop="ID"></el-table-column>
<el-table-column label="姓名" prop="Name"></el-table-column>
<el-table-column label="性别" prop="Sex"></el-table-column>
<el-table-column label="年龄" prop="Age"></el-table-column>
</el-table>
</div>
</template>
<script>
import axios from 'axios';
export default {
data: function () {
return {
"students": []
};
},
mounted: async function () {
const resp = await axios.get("/api/students")
this.students = resp.data.data
}
};
</script>
2. 分页组件
具体使用见:https://element.eleme.cn/#/zh-CN/component/pagination
分页常用的属性:
代码语言:javascript复制 <template>
<div>
<!-- 分页常用属性:
total属性:总条目数
page-size:每页显示条目个数,默认10条
current-page:当前页数
layout:控制分页条外观,
分页条可以看成由多个小的部分组成的
(比如:向上翻,向下翻,页码,跳转到第几页的数框,总记录数...)
这个layout就可以控制这些部分哪些显示,哪些不显示
默认是'prev, pager, next, jumper, ->, total'都显示
可选参数:sizes, prev, pager, next, jumper, ->, total, slot
page-sizes:每页显示个数选择器的选项设置,默认:[10, 20, 30, 40, 50, 100]
-->
<el-pagination v-bind:total="50" v-bind:page-size="5" layout="prev, pager, next, sizes, ->, total"></el-pagination>
</div>
</template>
<script>
export default {};
</script>
有人可能会好奇为什么有的属性加了v-bind,有的没有呢? 加了
v-bind
,就代表他的值来自于JavaScript,如果在option的data()返回的对象里找不到对应的绑定属性,就会将右侧当成表达式进行解析; 没有加:
的,等号右边的值就是他的最终结果。 例子::page-sizes="[5,10,15,20]"
如果加了:
会正常解析成数组,但是如果没加:
,就会当做字符串,而不是解析成数组。
分页常用的事件:
示例:
代码语言:javascript复制 <template>
<div>
<!-- data属性:关联表格需要展示的数据 -->
<el-table v-bind:data="students">
<!-- lable属性:这个列的标题 -->
<!-- prop属性:表格内部会遍历这个学生数组,那么学生对象的哪个属性需要显示在这一列上就使用到了prop -->
<el-table-column label="编号" prop="ID"></el-table-column>
<el-table-column label="姓名" prop="Name"></el-table-column>
<el-table-column label="性别" prop="Sex"></el-table-column>
<el-table-column label="年龄" prop="Age"></el-table-column>
</el-table>
<!-- 分页常用事件:
事件名称 说明 回调参数
current-change currentPage 改变时会触发 当前页
size-change pageSize 改变时会触发 每页条数
-->
<el-pagination
v-bind:total="total"
v-bind:page-size="queryPage.pageSize"
v-bind:current-page="queryPage.currentPage"
v-on:current-change="currentChange"
v-on:size-change="sizeChange"
v-bind:page-sizes="[2,3,5,7]"
layout='prev, pager, next, sizes,jumper, ->, total'>
</el-pagination>
</div>
</template>
<script>
import axios from 'axios';
export default {
data: function () {
return {
total: 0,
students: [],
queryPage: {
pageSize: 5, // 页大小
currentPage: 1, // 页码
},
};
},
methods: {
currentChange(page) {
this.queryPage.currentPage = page;
this.queryStudents()
},
sizeChange(size) {
this.queryPage.pageSize = size;
this.queryStudents()
},
async queryStudents() {
const resp = await axios.get("/api/students", {
params: this.queryPage,
})
this.students = resp.data.data.students;
this.total = resp.data.data.total;
},
},
mounted: function () {
this.queryStudents()
}
};
</script>
- 三种情况都应该触发查询
- mounted 组件挂载完成后
- 页号变化时
- 页大小变化时
- 查询传参应该根据后台需求,灵活采用不同方式
- 本例中因为是 get 请求,无法采用请求体,只能用 params 方式传参
- 返回响应的格式也许会很复杂,需要掌握【根据返回的响应结构,获取数据】的能力
3. 分页搜索
- 按姓名模糊搜索
- 按性别精确搜索
- 按年龄范围查询
<template>
<div>
<!-- 输入框 -->
<el-input placeholder="请输入姓名" v-model="queryDto.name"></el-input>
<!-- 下拉列表 -->
<el-select placeholder="请选择性别" v-model="queryDto.sex" clearable>
<el-option value="男"></el-option>
<el-option value="女"></el-option>
</el-select>
<!-- 下拉列表 -->
<!-- label:展示给用户看的样子 -->
<el-select placeholder="请选择年龄" v-model="queryDto.age" clearable>
<el-option value="0,18" label="0到18岁"></el-option>
<el-option value="19,30" label="19到30岁"></el-option>
<el-option value="31,40" label="31到40岁"></el-option>
<el-option value="41,120" label="41到120岁"></el-option>
</el-select>
<el-button type="primary" v-on:click="search()">搜索</el-button>
<el-table v-bind:data="students">
<el-table-column label="编号" prop="ID"></el-table-column>
<el-table-column label="姓名" prop="Name"></el-table-column>
<el-table-column label="性别" prop="Sex"></el-table-column>
<el-table-column label="年龄" prop="Age"></el-table-column>
</el-table>
<el-pagination v-bind:total="total" v-bind:page-size="queryDto.pageSize"
v-bind:current-page="queryDto.currentPage" v-on:current-change="currentChange" v-on:size-change="sizeChange"
v-bind:page-sizes="[2,3,5,7]" layout='prev, pager, next, sizes,jumper, ->, total'>
</el-pagination>
</div>
</template>
<script>
import axios from 'axios';
export default {
data: function () {
return {
total: 0,
students: [],
queryDto: {
pageSize: 5, // 页大小
currentPage: 1, // 页码
name: '',
sex: '',
age: ''
},
};
},
methods: {
currentChange(page) {
this.queryDto.currentPage = page;
this.queryStudents()
},
sizeChange(size) {
this.queryDto.pageSize = size;
this.queryStudents()
},
async queryStudents() {
const resp = await axios.get("/api/students", {
params: this.queryDto,
})
this.students = resp.data.data.students;
this.total = resp.data.data.total;
},
search() {
this.queryStudents()
}
},
mounted: function () {
this.queryStudents()
},
};
</script>
4. Cascader 级联选择器
级联选择器中选项的数据结构为:
代码语言:javascript复制 <!-- 多级菜单 -->
<template>
<div>
<el-cascader v-bind:options="ops"></el-cascader>
</div>
</template>
<script>
export default {
data:function(){
return {
// 多级菜单的数据
ops:[
{value:100,label:'主页',children:[
{value:101,label:'菜单1',children:[
{value:105,label:'子项1'},
{value:106,label:'子项2'},
]},
{ value: 102, label: '菜单2', children: [
{value:107,label:'子项3'},
{value:108,label:'子项4'},
{value:109,label:'子项5'},
]},
{ value: 103, label: '菜单3', children: [
{value:110,label:'子项6'},
{value:111,label:'子项7'},
] },
{value:104,label:'菜单4'},
]}
],
};
},
};
</script>
上面将选项数据写死在了javaScipt里,更合理的做法应该来自后端服务器:
数据准备:
代码语言:javascript复制 CREATE TABLE `menu`(
id INT,
name VARCHAR(10),
icon VARCHAR(30),
path VARCHAR(30),
pid INT,
PRIMARY KEY (id)
) COMMENT '菜单表';
INSERT INTO menu (id, name, icon, path, pid) values
(100,'主页','el-icon-menu','/',0),
(101,'菜单1','el-icon-menu','/menu1',100),
(105,'子项1','el-icon-menu','/menu1/c1',101),
(106,'子项2','el-icon-menu','/menu1/c2',101),
(102,'菜单2','el-icon-menu','/menu2',100),
(107,'子项3','el-icon-menu','/menu2/c3',102),
(108,'子项4','el-icon-menu','/menu2/c4',102),
(109,'子项5','el-icon-menu','/menu2/c5',102),
(103,'菜单3','el-icon-menu','/menu3',100),
(110,'子项6','el-icon-menu','/menu3/c6',103),
(111,'子项7','el-icon-menu','/menu3/c7',103),
(104,'菜单4','el-icon-menu','/menu4',100);
后端代码自己写,表里的数据是一维的,没有层级关系的,后端的人可以直接返给你有层级的关系的数据,但是如果他们不想写,而是给你返回一维的这种数组,那么前端就需要自己将这个一维的数组转换成这种树状的数据(这也是个基本功)。
下面的例子是将后端返回的一维数组【树化】
代码语言:javascript复制 <!-- 多级菜单 -->
<template>
<div>
<el-cascader v-bind:options="ops"></el-cascader>
</div>
</template>
<script>
import axios from 'axios';
export default {
data: function () {
return {
// 多级菜单的数据
// cascade级联选择器只需要最顶层的对象,就会从children里遍历子对象(所有只需要将最顶层的对象给他就行)。
ops: [],
};
},
mounted: async function () {
const resp = await axios.get("/api/menu");
const menus = resp.data.data;
// 1. 将所有数据存入map集合(为了接下来查找效率)
const map = new Map(); // set get
for (const { Id, Name, Pid } of menus) {
map.set(Id, { value: Id, label: Name, pid: Pid });
}
// 2. 建立父子关系
const top = [];
for (const obj of map.values()) {
if (obj.pid !== 0) {
const parent = map.get(obj.pid)
// 如果父节点还没定义子数组,就创建一个空的数组
if (parent.children === undefined) {
parent.children = [];
}
parent.children.push(obj);
} else {
// 3. 找到顶层对象,本例中顶层对象只有一个,但是实际上可能不止,所以使用数组
// cascade级联选择器只需要最顶层的对象,就会从children里遍历子对象(所有只需要将最顶层的对象给他就行)。
// 这个时候的top顶层对象是与所有子对象建立完联系了的
top.push(obj);
}
}
this.ops = top;
},
};
</script>
我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!