elementUI-day02----elementUI中涉及到组件嵌套的时候如何进行传值-slot插槽作用域、商家列表(shoplist、table表格固定列和表头、tag标签、分页、对话框-删除当前数据、对话框-编辑当前数据、对话框-推荐菜品 tag标签-动态编辑标签、搜索)、用户列表(userlist、分页、全选和非全选、steps步骤条)
### elementUI中涉及到组件嵌套的时候如何进行传值-slot插槽作用域
```vue <template> <zujian> <template slot-scope="props"> <p>{{props.row.属性}}</p> </template> </zujian> </template> ```
### 商家列表-shoplist
①mock下新建shop.js,利用mock定义后端接口 /shopmanage/shoplist:
import Mock from "mockjs"; let shopData=Mock.mock({ "data|40":[ { "id|+1":1001, "shopName":"@csentence(3, 5)", "shopAddress":"@city(true)", "shopTel":/^1(3|5|7|8|9)\d{9}$/, "shopDesc":"@csentence", "tag":()=>{ let arr=[ { text:"水煮鱼", type:"success" },{ text:"酸菜鱼", type:"info" },{ text:"炖大鹅", type:"danger" },{ text:"红烧排骨", type:"warning" } ]; let n=parseInt(1+Math.random()*arr.length); return arr.slice(0,n); }, } ] }) Mock.mock(/\/shopmanage\/shoplist/,"get",(options)=>{ let {limit,page}=JSON.parse(options.body); let arr=[]; /* 分页: 当page为1时,i为0~9 当page为2时,i为10~19 ... */ for(let i=limit*(page-1);i<limit*page;i++){ arr.push(shopData.data[i]); } return { dataList:arr, total:shopData.data.length }; })
②引入:
mock/index.js中:import "./shop.js";
main.js中:import "@mock/index.js";
③api/request.js中定义请求方法 shopListApi:
/* 商家列表 */ export const shopListApi = (shopInfo) => { return http({ method:"get", url:"/shopmanage/shoplist", data:shopInfo }) }
④pages/ShopManage/BusinessList/index.vue中请求数据,将limit和page传过去:
import { shopListApi } from "@api/request.js"; export default { name: "BusinessList", data() { return { tableData: [], shopInfo:{ limit:10, page:1 }, total:0 }; }, methods: { async getShopList(shopInfo){ let data=await shopListApi(shopInfo); this.tableData=data.dataList; this.total=data.total; } }, created() { this.getShopList(this.shopInfo); }, };
⑤pages/ShopManage/BusinessList/index.vue中渲染数据:
<el-table-column label="ID" prop="id"></el-table-column> <el-table-column label="店铺名称" prop="shopName"></el-table-column> <el-table-column label="店铺地址" prop="shopAddress"></el-table-column> <el-table-column label="联系电话" prop="shopTel"></el-table-column> <el-table-column label="店铺简介" prop="shopDesc"></el-table-column> <el-table-column label="推荐菜品" prop="tag"></el-table-column> <el-table-column label="操作"> <el-button size="small">编辑</el-button> <el-button size="small">删除</el-button> </el-table-column>
### 商家列表-table表格固定列和表头
<el-table></el-table>标签加上 height="500" 可以固定表头 <el-table-column></el-table-column>标签加上 fixed="left" 或 fixed="right" 可以固定列,但是要注意它的兄弟元素要加上width="300",全部兄弟元素的宽度加起来要大于父元素的宽度
### 商家列表-tag标签
pages/ShopManage/BusinessList/index.vue中:
<el-table-column label="推荐菜品" prop="tag" width="300"> <template slot-scope="props"> <div class="tag-group"> <el-tag v-for="(item,index) in props.row.tag" :key="index" :type="item.type" effect="light" >{{item}}</el-tag> </div> </template> </el-table-column>
注意:
1、elementUI中组件中嵌套其他组件,先写template标签
2、三元嵌套定义type: :type="parseInt(Math.random()*4)==0?'success':parseInt(Math.random()*4)==1?'info':parseInt(Math.random()*4)==2?'danger':parseInt(Math.random()*4)==3?'warning':''"
配置项:
effect 主题:默认是light,dark表示有背景色,plain表示无背景色
### 商家列表-分页
①pages/ShopManage/BusinessList/index.vue中给需要加分页的页面添加上分页的元素,绑定 current-change 事件:
<el-pagination background layout="prev, pager, next" :total="total" @current-change="handleChange"></el-pagination>
②pages/ShopManage/BusinessList/index.vue中书写 handleChange 方法:
handleChange(page){ this.shopInfo.page=page; this.getShopList(this.shopInfo); }
注意:事件函数不要带括号,事件函数的参数就是当前页数,将这个页数拿到重新请求数据即可。
### 商家列表-对话框-删除当前数据
①pages/ShopManage/BusinessList/index.vue中为删除按钮绑定click事件:
<el-table-column label="操作" fixed="right" width="150"> <template slot-scope="props"> <div> <el-button size="small" type="primary">编辑</el-button> <el-button size="small" type="danger" @click="handleDel(props.row)">删除</el-button> </div> </template> </el-table-column>
注意:这里的传值需要用template标签将编辑和删除按钮包裹,template标签添加slot-scope="props",在事件函数中可以通过props.row将当前整条信息传给函数。
②pages/ShopManage/BusinessList/index.vue中书写 handleDel 方法,利用MessageBox弹框:
handleDel(currentData) { this.$confirm(`此操作将永久删除<${currentData.shopName}>,是否继续?`,"提示",{confirmButtonText: "确定",cancelButtonText: "取消",type: "warning"}) .then(() => { /* 这里拿到当前数据currentData,主要是拿到id再向后端发送请求删除当前数据 */ console.log(currentData); this.$message({ type: "success", message: "删除成功!" }); }) .catch(() => { this.$message({ type: "info", message: "已取消删除" }); }); }
### 商家列表-对话框-编辑当前数据
对话框组件ShopDialog默认有个属性:visible.sync="dialogVisible"控制对话框的显示和隐藏。
父组件中给子组件ShopDialog传递自定义属性dialogVisible默认为false,点击编辑按钮给将dialogVisible改为true,这样点击按钮即可显示对话框。
关闭对话框:给<el-dialog>标签设置 :before-close="handleClose" ,该函数中触发父组件的自定义事件close,并且将false传递过去,在父组件中定义close的事件函数,再将dialogVisible的值设置为传来的false,就可以关闭对话框了。
①components下新建对话框:ShopDialog.vue(粘贴dialog的代码)
②pages/ShopManage/BusinessList/index.vue中引入并注册:
import ShopDialog from "@components/ShopDialog/index.vue";
components: { ShopDialog },
③pages/ShopManage/BusinessList/index.vue中渲染时传入自定义属性dialogVisible、dialogData:
<ShopDialog :dialogVisible="dialogVisible" :dialogData="dialogData"></ShopDialog>
④自定义属性在data中的默认值分别是false、{}
⑤给编辑按钮添加点击事件:
<el-table-column label="操作" fixed="right" width="150"> <template slot-scope="props"> <div> <el-button size="small" type="primary" @click="handleEdit(props.row)">编辑</el-button> <el-button size="small" type="danger" @click="handleDel(props.row)">删除</el-button> </div> </template> </el-table-column>
对应的方法:
handleEdit(currentData) { this.dialogData = currentData; // 显示对话框 this.dialogVisible = true; }
⑥components/ShopDialog.vue中可以通过props拿到dialogVisible和dialogData,但是因为单项数据流,所以这里通过watch将这两个值分别赋给dialogFlag和dialogInfo,在使用的时候用dialogFlag和dialogInfo:
data() { return { /* 单项数据流:子组件不能更改父组件传来的值 解决办法: 用dialogFlag替代dialogVisible 用dialogInfo替代dialogData */ dialogFlag: false, dialogInfo: {} }; }, props: { dialogVisible: { type: Boolean, default: false }, dialogData: { type: Object, default: {} } }, watch: { dialogVisible(newValue, oldValue) { this.dialogFlag = newValue; }, dialogData(newValue, oldValue) { this.dialogInfo = newValue; } }
⑦在关闭对话框的时候会出现不能再打开的bug,解决办法:
先在<el-dialog>标签中设置 :before-close="handleClose"
对应的方法:(触发父组件中的close事件)
methods: { // 关闭之前触发父组件的自定义事件close,将dialogVisible的值改为此处传过去的false,这样当关闭对话框之后还可以重新打开 handleClose() { this.$emit("close", false); } }
然后在父组件中定义自定义事件close:
<ShopDialog :dialogVisible="dialogVisible" :dialogData="dialogData" @close="handleClose"></ShopDialog>
对应的方法:(将dialogVisible属性再设置为false)
handleClose(flag) { this.dialogVisible = flag; }
在对话框组件中添加一个取消按钮就直接用点击事件,事件函数和:before-close一样:
<el-button @click="handleClose">取消</el-button>
⑧修改时的确认按钮:
<el-button type="primary" @click="confirm(dialogInfo)">确认</el-button>
对应的方法:
confirm(dialogInfo) { console.log(dialogInfo); /* 成功 */ this.$message({ message: "修改成功", type: "success", onClose:()=>{ this.$emit("close", false); } }); }
### 商家列表-对话框-推荐菜品 tag标签-动态编辑标签
①components/ShopDialog.vue中粘贴tag标签-动态编辑标签的代码:
<el-form-item label="推荐菜品:"> <!-- 默认数据 --> <el-tag v-for="(item,index) in dialogInfo.tag" :key="index" closable :disable-transitions="false" @close="handleTagClose(index)" >{{item.text}}</el-tag> <!-- 添加数据 --> <el-input class="input-new-tag" v-if="inputVisible" v-model="inputValue" ref="saveTagInput" size="small" @keyup.enter.native="handleInputConfirm" @blur="handleInputConfirm" ></el-input> <!-- 新增按钮 --> <el-button v-else class="button-new-tag" size="small" @click="showInput">添加推荐菜品</el-button> </el-form-item>
②data中定义inputVisible: false,inputValue: ""
③事件函数:
// 删除tag handleTagClose(i) { this.dialogInfo.tag.splice(i,1); }, // 点击添加显示input并聚焦 showInput() { this.inputVisible = true; this.$nextTick(_ => { this.$refs.saveTagInput.$refs.input.focus(); }); }, // 按下回车或者input失焦时触发 handleInputConfirm() { let inputValue = this.inputValue; if (inputValue) { this.dialogInfo.tag.push({text:inputValue,type:"success"}); } this.inputVisible = false; this.inputValue = ""; }
此时,点击确认按钮可以拿到完整的修改过的数据。
### 商家列表-搜索
①el-form下el-form-item下放el-input或者el-search,注意:组件内嵌套需要用到template:
<el-form inline :model="search_model"> <el-form-item label="商家名称"> <el-input v-model="search_model.shopName" @input="handleShopNameChange"></el-input> </el-form-item> <el-form-item label="菜品推荐"> <!-- 组件内嵌套需要用到template --> <template> <el-select v-model="search_model.shopRecommendVal" placeholder="请选择" @change="handleShopRecommendChange"> <el-option v-for="item in search_model.shopRecommend" :key="item.text" :label="item.text" :value="item.text" ></el-option> </el-select> </template> </el-form-item> <el-form-item label="销量"> <template> <el-select v-model="search_model.volumeVal" placeholder="请选择"> <el-option v-for="(item,index) in search_model.volume" :key="index" :label="item" :value="item" ></el-option> </el-select> </template> </el-form-item> <el-form-item> <el-button>搜索</el-button> </el-form-item> </el-form>
②对应的data数据:
search_model:{ shopName:"", shopReco mmendVal:"", volumeVal:"降序", shopRecommend:[ { text:"水煮鱼", type:"success" },{ text:"酸菜鱼", type:"info" },{ text:"炖大鹅", type:"danger" },{ text:"红烧排骨", type:"warning" } ], volume:["升序","降序"] }
③事件函数:
// 菜品推荐change事件 handleShopRecommendChange(value){ // 进行数据请求,后端进行关键字查询,返回查询结果 console.log(value) }, // 商品名称input事件 handleShopNameChange(value){ // 进行数据请求,后端进行关键字查询,返回查询结果 console.log(value) }
### Moment.js
时间戳--->日期格式化
### 用户列表-userlist
①elementUI中粘贴一段table组件,改啵改啵:
<el-table :data="tableData" style="width: 100%" height="500" border> <el-table-column type="selection" width="55"></el-table-column> <el-table-column fixed prop="id" label="用户ID" width="150"></el-table-column> <el-table-column prop="username" label="停用/启用" width="120"> <template> <el-switch v-model="value1" active-text="启用" inactive-text="停用"></el-switch> </template> </el-table-column> <el-table-column prop="name" label="登录账号" width="120"></el-table-column> <el-table-column prop="fullname" label="真实姓名" width="120"></el-table-column> <el-table-column prop="province" label="用户角色" width="120"></el-table-column> <el-table-column prop="firstTimeDate" label="注册时间" width="160"></el-table-column> <el-table-column prop="address" label="邮箱地址" width="300"></el-table-column> <el-table-column prop="lastTimeDate" label="最近登录时间" width="160"></el-table-column> <el-table-column label="操作" width="200" fixed="right"> <template> <div> <el-button size="small">永久删除</el-button> <el-button size="small">权限设置</el-button> </div> </template> </el-table-column> </el-table>
②data数据支持:(value1是给启用/停用用的,tableData是table所依赖的数据,userInfo是给后端传递的请求参数)
data() { return { value1:true, tableData: [], userInfo: { limit: 10, page: 1 }, total:0 }; }
③mock下新建user.js:(mock数据:模拟后端请求数据,写完之后在index.js中引入以下:import "./user.js";)
import Mock from "mockjs"; let userData=Mock.mock({ "data|100":[ { "id|+1":100, "status":()=>{ if(Math.random()>0.5){ return true; }else{ return false; } }, "username":"@email()", "fullname":"@cname", "auth":()=>{ let arr=["超级管理员","管理员","普通用户","部门主管"]; let n=parseInt(Math.random()*4); return arr[n]; }, "firstTimeDate":"@date(yyyy-MM-dd hh:mm:ss)", "email":"@email()", "lastTimeDate":"@date(yyyy-MM-dd hh:mm:ss)" } ] }) /* 用户列表 */ Mock.mock(/\/usermanage\/userlist/,"get",(options)=>{ let {limit,page}=JSON.parse(options.body); let arr=[]; /* 分页: 当page为1时,i为0~9 当page为2时,i为10~19 ... */ for(let i=limit*(page-1);i<limit*page;i++){ arr.push(userData.data[i]); } return { dataList:arr, total:userData.data.length }; })
④api/request.js中声明用户列表的接口userListApi:
/* 用户列表 */ export const userListApi = (userInfo) => { return http({ method:"get", url:"/usermanage/userlist", data:userInfo }) }
⑤UserList.vue中引入接口并请求数据(userInfo参数是data中定义的,后面写分页只需要切换page的值):
import {userListApi} from "@api/request.js"; methods: { async getUserList(userInfo){ let data=await userListApi(userInfo); console.log(data) this.tableData=data.dataList; } }, created() { this.getUserList(this.userInfo); }
注意:停用/启用的状态,去掉el-table-column标签中的prop属性,在template中用slot-scope="props"传值
<el-table-column label="停用/启用" width="120"> <template slot-scope="props"> <el-switch v-model="props.row.status" active-text="启用" inactive-text="停用"></el-switch> </template> </el-table-column>
el-table-column标签里没有嵌套子组件的时候,这个标签直接用prop属性读取数据
如果有嵌套子组件,就要用template标签把子组件包裹,template标签上slot-scope="props"固定写法,然后子组件中用props.row.属性 去读取属性
### 用户列表-分页
①pages/UserManage/UserList.vue中添加分页器,声明current-change事件,事件函数不要带括号:
<el-pagination background layout="prev, pager, next" :total="total" @current-change="handleChange"></el-pagination>
②事件函数:
handleChange(page){ this.userInfo.page=page; this.getUserList(this.userInfo); }
③在getUserList()方法中,将获取的total的值赋给data中total:
this.total=data.total;
### 用户列表-启用/停用的处理
①给当前组件添加change事件:
<el-table-column label="停用/启用" width="150"> <template slot-scope="props"> <el-switch v-model="props.row.status" active-text="启用" inactive-text="停用" @change="handleStatusChange(props.row)"></el-switch> </template> </el-table-column>
②事件处理函数:
handleStatusChange(data){ console.log(data) console.log(data.status) // 这里做请求 }
### 用户列表-全选和非全选
①给<el-table></el-table>组件绑定@selection-change事件:
<el-table :data="tableData" style="width: 100%" height="500" border @selection-change="handleSelectionChange">
②对应的事件函数,每次做点击都会有个arr表示当前已勾选数据,接下来进行数据请求:
handleSelectionChange(dataList){ // 一般用来做批量删除 }
### 商品列表-steps步骤条
①pages/ShopManage/BusinessManage/index.vue中引入elementUI中的Steps“居中的步骤条”:
<div class="businessManage"> <el-steps :active="active" align-center> <el-step title="个人基本信息" description="请正确填写您的基本信息"></el-step> <el-step title="手机号验证" description="确保用户的安全请绑定手机号微信号"></el-step> <el-step title="银行卡绑定" description="收入金额请绑定银行卡"></el-step> <el-step title="权限验证" description="操作请进行权限验证"></el-step> </el-steps> <div> <el-button @click="prev">上一步</el-button> <el-button @click="next">下一步</el-button> <el-button @click="submit">提交</el-button> </div> <keep-alive> <component :is="conName"></component> </keep-alive> </div>
注意:active是当前高亮
②pages/ShopManage/BusinessManage下新建components文件夹,新建One、Two、Three、Four四个组件:
<template> <div> one <el-form :model="oneModel"> <el-form-item> <el-input type="text" v-model="oneModel.inputVal"></el-input> </el-form-item> </el-form> </div> </template> <script> export default { data() { return { oneModel:{ inputVal:"" } } }, } </script>
③pages/ShopManage/BusinessManage/index.vue中引入四个组件并对应的逻辑:
<script> import One from "./components/One.vue"; import Two from "./components/Two.vue"; import Three from "./components/Three.vue"; import Four from "./components/Four.vue"; export default { name: "BusinessManage", data() { return { conName:"One", active:0 } }, components:{One,Two,Three,Four}, methods: { prev(){ if(this.active==0){ this.active=0; }else{ this.active--; } this.handleToggle(); }, next(){ if(this.active==4){ this.active==4; }else{ this.active++; } this.handleToggle(); }, submit(){ }, handleToggle(){ switch(this.active){ case 1: this.conName="One"; break; case 2: this.conName="Two"; break; case 3: this.conName="Three"; break; case 4: this.conName="Four"; break; default: this.conName="One"; } } }, }; </script>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 提示词工程——AI应用必不可少的技术
· 字符编码:从基础到乱码解决
· 地球OL攻略 —— 某应届生求职总结