Vue element商品列表的增删改功能实现
目录
- 介绍
- 基本信息
- 上传主图
- 商品信息vue富文本编辑器的配置
- 最后提交数据
介绍
整体和用户列表 类似 功能步骤有:
- 面包屑导航
- 外部是大的卡片组件
- 搜索商品 添加商品
- 表格渲染数据
- 作用域插槽用于 操作按钮
- 分页器组件的使用
不一样的点:之前编辑信息 新增信息是 弹出对话框编辑 但商品信息内容较多 我们跳转到一个组件、并且进行商品编辑的时候要进行路由传参 来渲染初始数据
点击添加商品按钮时跳转到新增商品组件对应路径:
addGoods(){ this.$router.push('/goods/add') }
点击编辑商品按钮时跳转到编辑商品组件对应路径 并且传入id
ToEditGoods(id){ this.$router.push(`/goods/edit/${id}`) }
新增商品和编辑商品组件布局一致只是新增商品 不用 传参请求数据
我们以编辑商品为例
在设置路由对应关系的时候 预留占位符
{ path:'/goods', component:GoodsList }, { path:'/goods/add', component:GoodsAdd }, { path:'/goods/edit/:id', component:GoodsEdit }
第一步 先使用组件进行页面布局:
主要使用到了 el-steps 步骤条组件 和 el-tabs 标签页组件的联动 使他们步长一致 使用共同的
active 步骤条的active 动态绑定 到 activeIndex上
当标签页发生切换时 根据name 赋值给 activeIndex
async handleClick(){ this.activeIndex = this.activeName * 1 // 选择了商品(动态)参数选项 },
这样 两个组件就可以联动展示了
标签页组件其实是包裹在 el-form 当中方便统一提交给服务器
接下来就是表单内部 组件渲染 表单验证了
基本信息
组件渲染el-input 数据绑定 v-model 类型限制 tpye=‘number’ prop合法值验证
这里需要自定义验证的是 商品价格不能小于0 商品数量必须是整数
必填就可以直接使用自带的
基本信息中还有一个要点:分类选择
<el-form-item label="选择商品分类"> el-cascader 级联选择器 <el-cascader 默认选定的值是根据id请求过来的分类数组 v-model="AddGoodsForm.goods_cat" style="width: 400px" 数据来源:cateLists 一进入页面请求过来的 :options="cateLists" 有清空按钮 clearable 禁用 编辑页面 不让修改分类 disabled 级联选择器的相关规则 :props="CSet" 选择发生改变时 执行的回调 @change="handleChange"></el-cascader> </el-form-item> <script> 数据来源: async getAllCate(){ const {data:res} = await this.$http.get('categories') if (res.meta.status !==200) return this.$Msg.error('获取商品分类列表失败!') this.cateLists = res.data } 级联选择器的规则 CSet:{ 展示下一级触发方式 鼠标悬浮 expandTrigger: 'hover', 指定选项的子选项为选项对象的某个属性值 children:'children', 显示的文本 label:'cat_name', 文本对应的value value:'cat_id', } 选择发生改变时 执行的回调 只让选择第三级 不是的话就清空 选择不进去 handleChange(){ if (this.AddGoodsForm.goods_cat.length !== 3){ this.AddGoodsForm.goods_cat = [] } console.log(this.AddGoodsForm.goods_cat) } <script>
如果是新增商品页面的话 也大体一致 把 disabled 去掉即可
并且在切换标签页时可以验证AddGoodsForm.goods_cat 的长度
leaveTabs(activeName, oldActiveName){ if(oldActiveName === '0' && this.AddGoodsForm.goods_cat.length !== 3){ this.$Msg.error('请先选择商品分类!') return false }
根据服务器返回的数据
渲染商品参数-attr.many 和商品属性-attr.only
分别渲染 多选框组和输入框组来v-for 循环
上传主图
<el-tab-pane label="4.商品图片" name="3"> <el-upload class="upload-demo" :action="actionToUrl" :on-preview="handlePreview2" :on-remove="handleRemove" :on-success="handleSuccess" :headers="UploadHeaders" list-type="picture-card"> <el-button size="small" type="primary">点击上传</el-button> <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div> </el-upload> </el-tab-pane> <el-dialog title="预览图片" :visible.sync="Preview" width="45%"> <img :src="PreviewPic" alt="" style="width: 100%"> <span slot="footer" class="dialog-footer"> <el-button type="primary" @click="Preview = false">确 定</el-button> </span> </el-dialog> <script> action 必选参数,上传的地址 这里用的是本地服务器 actionToUrl:'http://127.0.0.1:8888/api/private/v1/upload' on-preview 点击文件列表中已上传的文件时的钩子 点击出现对话框显示放大预览图 handlePreview2(file){ this.PreviewPic=file.response.data.url // 显示图片的地址 this.Preview = true // 决定对话框显示的布尔值 } on-remove 文件列表移除文件时的钩子 handleRemove(file){ //1.获取将要删除的图片临时路径 const fileUrl = file.response.data.tmp_path //2.从pics 数组中,找到这个图片对应的索引值 let aaa = this.AddGoodsForm.pics.findIndex(value => value === fileUrl) console.log(aaa) //3.调用数组 splice 方法 把图片信息对象从pics 数组中移除 this.AddGoodsForm.pics.splice(aaa,1) console.log(this.AddGoodsForm.pics) } on-success 文件上传成功时的钩子 async handleSuccess(response){ // 找出定义一下 新上传文件的路径地址 const NewPicUrl = response.data.tmp_path // push 到预留表单位中 this.AddGoodsForm.pics.push(NewPicUrl) console.log(this.AddGoodsForm.pics) // const {data:res} = await this.$http.put(`goods/${this.NowEditId}/pics`,this.AddGoodsForm.pics) // if (res.meta.status !==200) return this.$Msg.error('更新主图失败!') // this.$Msg.success('更新主图成功!') } headers 设置上传的请求头部 UploadHeaders:{ Authorization:window.sessionStorage.getItem('token') }, </script>
商品信息vue富文本编辑器的配置
先执行安装语句:
在main.js 中注册 并引入样式
npm install vue-quill-editor import VueQuillEditor from 'vue-quill-editor' import 'quill/dist/quill.core.css' // import styles import 'quill/dist/quill.snow.css' // for snow theme import 'quill/dist/quill.bubble.css' // for bubble theme Vue.use(VueQuillEditor, /* { default global options } */)
在组件中使用
<el-tab-pane label="5.商品内容" name="4"> <quill-editor ref="myQuillEditor" 数据双向绑定 便于发送请求 v-model="AddGoodsForm.goods_introduce" 富文本编辑器的核心配置 :options="editorOption" /> </el-tab-pane> <script> // 此处定义在data外 const toolbarOptions = [ ['insertMetric'], ['bold', 'italic', 'underline', 'strike'], // 加粗,斜体,下划线,删除线 ['blockquote', 'code-block'], //引用,代码块 [{ 'header': 1 }, { 'header': 2 }], // 几级标题 [{ 'list': 'ordered' }, { 'list': 'bullet' }], // 有序列表,无序列表 [{ 'script': 'sub' }, { 'script': 'super' }], // 下角标,上角标 [{ 'indent': '-1' }, { 'indent': '+1' }], // 缩进 [{ 'direction': 'rtl' }], // 文字输入方向 [{ 'size': ['small', false, 'large', 'huge'] }], // 字体大小 [{ 'header': [1, 2, 3, 4, 5, 6, false] }], // 标题 [{ 'color': [] }, { 'background': [] }], // 颜色选择 [{ 'font': ['SimSun', 'SimHei', 'Microsoft-YaHei', 'KaiTi', 'FangSong', 'Arial'] }], // 字体 [{ 'align': [] }], // 居中 ['clean'], // 清除样式, ['link', 'image'] // 上传图片、上传视频 ] // toolbar标题 const titleConfig = [ { Choice: '.ql-insertMetric', title: '跳转配置' }, { Choice: '.ql-bold', title: '加粗' }, { Choice: '.ql-italic', title: '斜体' }, { Choice: '.ql-underline', title: '下划线' }, { Choice: '.ql-header', title: '段落格式' }, { Choice: '.ql-strike', title: '删除线' }, { Choice: '.ql-blockquote', title: '块引用' }, { Choice: '.ql-code', title: '插入代码' }, { Choice: '.ql-code-block', title: '插入代码段' }, { Choice: '.ql-font', title: '字体' }, { Choice: '.ql-size', title: '字体大小' }, { Choice: '.ql-list[value="ordered"]', title: '编号列表' }, { Choice: '.ql-list[value="bullet"]', title: '项目列表' }, { Choice: '.ql-direction', title: '文本方向' }, { Choice: '.ql-header[value="1"]', title: 'h1' }, { Choice: '.ql-header[value="2"]', title: 'h2' }, { Choice: '.ql-align', title: '对齐方式' }, { Choice: '.ql-color', title: '字体颜色' }, { Choice: '.ql-background', title: '背景颜色' }, { Choice: '.ql-image', title: '图像' }, { Choice: '.ql-video', title: '视频' }, { Choice: '.ql-link', title: '添加链接' }, { Choice: '.ql-formula', title: '插入公式' }, { Choice: '.ql-clean', title: '清除字体格式' }, { Choice: '.ql-script[value="sub"]', title: '下标' }, { Choice: '.ql-script[value="super"]', title: '上标' }, { Choice: '.ql-indent[value="-1"]', title: '向左缩进' }, { Choice: '.ql-indent[value="+1"]', title: '向右缩进' }, { Choice: '.ql-header .ql-picker-label', title: '标题大小' }, { Choice: '.ql-header .ql-picker-item[data-value="1"]', title: '标题一' }, { Choice: '.ql-header .ql-picker-item[data-value="2"]', title: '标题二' }, { Choice: '.ql-header .ql-picker-item[data-value="3"]', title: '标题三' }, { Choice: '.ql-header .ql-picker-item[data-value="4"]', title: '标题四' }, { Choice: '.ql-header .ql-picker-item[data-value="5"]', title: '标题五' }, { Choice: '.ql-header .ql-picker-item[data-value="6"]', title: '标题六' }, { Choice: '.ql-header .ql-picker-item:last-child', title: '标准' }, { Choice: '.ql-size .ql-picker-item[data-value="small"]', title: '小号' }, { Choice: '.ql-size .ql-picker-item[data-value="large"]', title: '大号' }, { Choice: '.ql-size .ql-picker-item[data-value="huge"]', title: '超大号' }, { Choice: '.ql-size .ql-picker-item:nth-child(2)', title: '标准' }, { Choice: '.ql-align .ql-picker-item:first-child', title: '居左对齐' }, { Choice: '.ql-align .ql-picker-item[data-value="center"]', title: '居中对齐' }, { Choice: '.ql-align .ql-picker-item[data-value="right"]', title: '居右对齐' }, { Choice: '.ql-align .ql-picker-item[data-value="justify"]', title: '两端对齐' } ] // 此处书写在data当中 editorOption: { placeholder: '请在这里输入......', theme: 'snow', //主题 snow/bubble modules: { history: { delay: 1000, maxStack: 50, userOnly: false }, toolbar: { container: toolbarOptions, handlers: { insertMetric: this.showHandle } } } } // 此处书写在 methods 中 // 配置富文本编辑器 initTitle () { document.getElementsByClassName('ql-editor')[0].dataset.placeholder = '' for (let item of titleConfig) { let tip = document.querySelector('.quill-editor ' + item.Choice) if (!tip) continue tip.setAttribute('title', item.title) } }, showHandle () { this.$Msg.error('这是自定义工具栏的方法!') }, // 自定义按钮内容初始化 initButton () { const editorButton = document.querySelector('.ql-insertMetric') editorButton.innerHTML = '<i class="el-icon-link" style="font-size: 18px;color:black"></i>' }, // 失去焦点 onEditorBlur (editor) { }, // 获得焦点 onEditorFocus (editor) { }, // 开始 onEditorReady (editor) { }, // 值发生变化 onEditorChange (editor) { // 如果需要手动控制数据同步,父组件需要显式地处理changed事件 // this.content = editor.html; console.log(editor); }, </script>
最后提交数据
<el-tab-pane label="6.提交商品" name="5"> <el-empty image="http://www.wsg3096.com/gangback/pub/asdc1.png" :image-size="320" description="确定所有数据添加完毕后就可以提交啦!"> <el-button type="primary" icon="el-icon-success" @click="ToGoods">上传商品</el-button> </el-empty> </el-tab-pane> <script> // 确定上传的按钮 async ToGoods(){ this.$refs.AddGoodsFormRef.validate(async valid =>{ if (!valid) return this.$Msg.error('请检查下各项数据是否规范!') // 执行添加业务的逻辑 先深拷贝一下 防止改变 级联选择器 const form = _.cloneDeep(this.AddGoodsForm) // 处理当前商品所属ID 服务器要求 ,分割的字符串 form.goods_cat = form.goods_cat.join(',') // 请求过来的数据保存到ManyData OnlyData 展示 返回去的时候 还用服务器的数据就行 form.attrs = [...this.ManyData,...this.OnlyData] // console.log(form) const {data : res} = await this.$http.put(`goods/${this.NowEditId}`,form) if (res.meta.status !== 200) return this.$Msg.error('编辑商品失败!') this.$Msg.success('编辑商品成功!') await this.$router.push('/goods') }) } </script>
到此这篇关于Vue element商品列表的增删改功能实现的文章就介绍到这了,更多相关Vue element商品列表内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!