项目仓库:https://github.com/changeclass/vue-shop
UI实现
时间格式化问题:可以设置一个全局的过滤器,对时间进行过滤
1 2 3 4 5 6 7 8 9 10 11 12 13
| Vue.filter('dataFormat', function(originVal) { const dt = new Date(originVal) const y = dt.getFullYear() const m = (dt.getMonth() + 1 + '').padStart(2, '0') const d = (dt.getDate() + 1 + '').padStart(2, '0')
const hh = (dt.getHours() + 1 + '').padStart(2, '0') const mm = (dt.getMinutes() + 1 + '').padStart(2, '0') const ss = (dt.getSeconds() + 1 + '').padStart(2, '0')
return `${y}-${m}-${d} ${hh}:${mm}:${ss}` })
|
1 2 3 4 5
| <el-table-column width="140px" label="创建时间" prop="add_time"> <template v-slot="scope"> {{ scope.row.add_time | dataFormat }} </template> </el-table-column>
|
其余部分参照ElementUI组件即可。
删除商品
为删除按钮绑定事件,事件内做出删除的动作即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| async removeById (id) { const result = await this.$confirm('是否要删除', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).catch(err => err) if (result !== 'confirm') { return this.$message.info('取消了操作') } else { const { data: res } = await this.$http.delete(`goods/${id}`) if (res.meta.status !== 200) { return this.$message.error('删除失败') } this.$message.success('删除成功') this.getGoodsList() } }
|
添加商品页面
步骤条
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <el-steps :space="200" :active="activeIndex" finish-status="success" align-center > <el-step title="基本信息"></el-step> <el-step title="商品参数"></el-step> <el-step title="商品属性"></el-step> <el-step title="商品图片"></el-step> <el-step title="商品内容"></el-step> <el-step title="完成"></el-step> </el-steps>
|
侧边tab
1 2 3 4 5 6 7
| <el-form :model="addForm" :rules="addFormRules" ref="addFormRef" label-width="100px" label-position="top" ></el-form>
|
通过属性label-position
属性进行设置tab栏的位置。
通过before-leave
事件进行设置当标签页切换时的事件,其值为一个函数。
1 2 3 4 5 6
| beforeTabLeave (activeName, oldActiveName) { if (oldActiveName === '0' && this.addForm.goods_cat.length !== 3) { this.$message.error('请先选择商品分类!') return false } }
|
级联选择器
1 2 3 4 5 6 7 8 9 10 11
| <el-cascader v-model="addForm.goods_cat" :options="cateList" :props="{ expandTrigger: 'hover', label: 'cat_name', value: 'cat_id', children: 'children', }" @change="handleChange" ></el-cascader>
|
商品参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <el-tab-pane name="1" label="商品参数"> <el-form-item :label="item.attr_name" v-for="item in manyTableData" :key="item.attr_id" > <el-checkbox-group v-model="item.attr_vals"> <el-checkbox v-for="(cb, i) in item.attr_vals" :key="i" :label="cb" border ></el-checkbox> </el-checkbox-group> </el-form-item> </el-tab-pane>
|
商品参数页面使用checkbox
组件,循环遍历attr_vals
每一项。但attr_vals
是一个字符串,因此在tabClicked
事件中重新处理下数据。将其转换为数组。
1 2 3 4 5 6 7 8 9 10 11 12
| async tabClicked () { if (this.activeIndex) { const { data: res } = await this.$http.get(`categories/${this.cateId}/attributes`, { params: { sel: 'many' } }) if (res.meta.status !== 200) { return this.$message.error('获取动态参数列表失败') } res.data.forEach(item => { item.attr_vals = item.attr_vals.length === 0 ? [] : item.attr_vals.split(' ') }) this.manyTableData = res.data } }
|
图片上传
图片上传的组件
1 2 3 4 5 6 7 8
| <el-upload action="http://127.0.0.1:8888/api/private/v1/upload" :on-preview="handlePreview" :on-remove="handleRemove" list-type="picture" :headers="headerObj" :on-success="handleSuccess" >
|
action
表示上传的地址
on-preview
点击文件列表中已上传的文件时的钩子
on-remove
图片移除时触发的事件
headers
发送请求时携带的请求头
on-success
图片上传成功时触发的函数
1 2 3 4 5 6
| handleRemove (file) { const filePath = file.response.data.tmp_path const i = this.addForm.pics.findIndex(x => x.pic === filePath) this.addForm.pics.splice(i, 1) }
|
1 2 3 4 5
| handleSuccess (res) { const picInfo = { pic: res.data.tmp_path } this.addForm.pics.push(picInfo) }
|
点击图片时会触发on-preview
事件,因此当触发此事件时保存下图片的路径并展示对话框即可。
1 2 3
| <el-dialog title="预览图片" :visible.sync="previewVisible" width="50%"> <img :src="previewPath" class="previewImg" /> </el-dialog>
|
1 2 3 4
| handlePreview (file) { this.previewPath = file.response.data.url this.previewVisible = true },
|
编辑器
安装依赖vue-quill-editor
入口文件导入并注册全局
1 2 3 4 5 6
| import VueQuillEditor from 'vue-quill-editor' import 'quill/dist/quill.core.css' import 'quill/dist/quill.snow.css' import 'quill/dist/quill.bubble.css'
Vue.use(VueQuillEditor)
|
提交商品
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| add () { this.$refs.addFormRef.validate(async valid => { if (!valid) { return this.$message.error('请填写必要的表单项') } const form = _.cloneDeep(this.addForm) form.goods_cat = form.goods_cat.join(',') this.manyTableData.forEach(item => { const newInfo = { attr_id: item.attr_id, attr_value: item.attr_vals.join(' ') } this.addForm.attrs.push(newInfo) }) this.onlyTableData.forEach(item => { const newInfo = { attr_id: item.attr_id, attr_value: item.attr_vals } this.addForm.attrs.push(newInfo) }) form.attrs = this.addForm.attrs const { data: res } = await this.$http.post('goods', form) if (res.meta.status !== 201) { return this.$message.error('添加商品失败') } this.$message.success('添加商品成功') this.$router.push('/goods') }) }
|