商品列表和新增商品(五)
阿新 • • 發佈:2020-08-27
實現的功能
功能 | 詳述 |
---|---|
商品列表 | 渲染元件和子路由;佈局;獲取和渲染商品列表;自定義格式化時間全域性過濾器;搜尋和清空;刪除商品 |
新增商品頁 | 渲染元件和子路由;佈局;步驟條;縱向Tab頁;步驟條和標籤頁聯動 |
基本資訊表單 | 商品分類使用級聯選擇器,只允許選中三級;阻止標籤頁切換 |
動態引數頁 | 複選框tag;根據不同tab頁執行不同操作 |
圖片上傳 | 渲染元件;圖片上傳;圖片刪除;圖片預覽 |
富文字編輯器 | |
新增商品 | 深拷貝 |
使用到的Element-ui元件
元件名稱_EN | 註冊 | 備註 |
---|---|---|
Steps | Vue.use(Steps) | 步驟條 |
Step | Vue.use(Step) | |
CheckboxGroup | Vue.use(CheckboxGroup) | 多選框 |
Checkbox | Vue.use(Checkbox) | |
Upload | Vue.use(Upload) | 上傳 |
使用到的依賴
執行依賴,富文字編輯器vue-quill-editor
// [main.js] // 匯入富文字編輯器 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)
執行依賴,lodash深拷貝lodash
// [Add.vue -> methods]
import _ from 'lodash'
一、商品列表
1.渲染元件和子路由
2.佈局
①麵包屑導航
②卡片檢視
③柵格系統 搜尋框 新增按鈕
④表格
⑤分頁
3.獲取渲染商品列表
①獲取商品列表
②渲染商品列表
1️⃣自定義格式化時間全域性過濾器
// [main.js] 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() + '').padStart(2, '0') const hh = (dt.getHours() + '').padStart(2, '0') const mm = (dt.getMinutes() + '').padStart(2, '0') const ss = (dt.getSeconds() + '').padStart(2, '0') return `${y}-${m}-${d} ${hh}:${mm}:${ss}` })
<!-- [GoodsList.vue] -->
<el-table-column label="建立時間" width="140px">
<template slot-scope="scope">{{scope.row.add_time | dataFormat}}</template>
</el-table-column>
4、搜尋和清空
5、根據Id刪除商品
6、新增商品頁跳轉
1️⃣程式設計式導航
// [GoodsList.vue]
goAddpage(){
this.$router.push('/goods/add')
}
// [index.js]
const routes = [
// ......
{path:'/goods/add',component:Add},
// ......
]
二、新增商品頁
1.渲染元件和子路由
2.佈局
①麵包屑導航
②卡片檢視
③警告
④步驟條Steps
:active="activeIndex-0":啟用項
<!-- [Add.vue] -->
<!-- 步驟條 -->
<el-steps :space="200" :active="activeIndex-0" 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>
// [Add.vue -> data]
activeIndex: '0'
/* [assets/css/global.css] */
.el-steps{
margin: 15px 0;
}
.el-step__title{
font-size: 13px;
}
⑤縱向標籤頁Tabs
<!-- [Add.vue] -->
<el-tabs
:tab-position="'left'"
v-model="activeIndex"
:before-leave="beforeTabLeave"
@tab-click="tabClicked"
>
<el-tab-pane label="基本資訊" name="0"></el-tab-pane>
<el-tab-pane label="商品引數" name="1"></el-tab-pane>
<el-tab-pane label="商品圖片" name="3"></el-tab-pane>
<el-tab-pane label="商品內容" name="4"></el-tab-pane>
</el-tabs>
⑥步驟條和標籤頁聯動
activeIndex: '0',
步驟條:active
轉換activeIndex為數值
標籤頁:v-model
啟用的name會繫結到v-model上
⑦表單
使用form包裹tabs,el-tabs必須和el-tab-pane巢狀
3、基本資訊
①渲染基本資訊表單
1️⃣商品分類使用級聯選擇器,只允許選中三級
// [Add.vue -> methods]
// 級聯選擇器選中項變化
handleChange() {
// 選中的不是三級分類
if (this.addForm.goods_cat.length !== 3) {
this.addForm.goods_cat = []
}
}
2️⃣阻止標籤頁切換
:before-leave="beforeTabLeave":標籤頁屬性,離開時觸發
oldActiveName:離開的標籤頁name
activeName:進入的標籤頁name
// [Add.vue -> methods]
beforeTabLeave(activeName, oldActiveName) {
if (oldActiveName === '0' && this.addForm.goods_cat.length !== 3) {
this.$message.error('請先選擇商品分類')
return false
}
}
②獲取商品分類資料
4、動態引數
①獲取動態引數
@tab-click="tabClicked":標籤頁屬性,點選時觸發,可以獲取activeIndex訪問的tab面板
// [Add.vue -> methods]
async tabClicked() {
if (this.activeIndex === '1') {
// 訪問動態引數面板
// ......
} else if (this.activeIndex === '2') {
// 訪問靜態屬性面板
// ......
}
},
②渲染動態引數
// [Add.vue -> methods]
async tabClicked() {
if (this.activeIndex === '1') {
// ......
res.data.forEach((item) => {
item.attr_vals =
item.attr_vals.length === 0 ? [] : item.attr_vals.split(',')
})
}
// ......
}
<!-- [Add.vue] -->
<el-tab-pane label="商品引數" name="1">
<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 :label="cb" v-for="(cb,i) in item.attr_vals" :key="i" border></el-checkbox>
</el-checkbox-group>
</el-form-item>
</el-tab-pane>
5、靜態屬性
①獲取靜態屬性
②渲染靜態屬性
6、圖片上傳
action:圖片上傳的api地址
:on-preview:圖片預覽
:on-remove:刪除圖片
:headers:上傳的請求頭
:on-success:圖片上傳成功後處理操作
①渲染圖片+上傳
<!-- [Add.vue] -->
<el-tab-pane label="商品圖片" name="3">
<!-- 上傳 -->
<el-upload
:action="uploadURl"
:on-preview="handlePreview"
:on-remove="handleRemove"
list-type="picture"
:headers="headerObj"
:on-success="handleSuccess"
>
<el-button size="small" type="primary">點選上傳</el-button>
</el-upload>
</el-tab-pane>
// [Add.vue -> data]
uploadURl: 'http://127.0.0.1:8888/api/private/v1/upload',
// 圖片上傳的headers請求頭物件
headerObj: {
Authorization: window.sessionStorage.getItem('token'),
},
// [Add.vue -> methods]
// 監聽圖片上傳成功
handleSuccess(response) {
// 1,拼接得到一個圖片資訊物件
const picInfo = { pic: response.data.tmp_path }
//2,將圖片資訊物件,push 到pics陣列中
this.addForm.pics.push(picInfo)
},
②圖片移除
// 處理移除圖片
handleRemove(file) {
// 1,獲取將要刪除的圖片的臨時路徑
const filePath = file.response.data.tmp_path
// 2.從pics陣列中,找到這個圖片對應的索引值
const i = this.addForm.pics.findIndex((x) => x.pic === filePath)
// 3.呼叫陣列的 splice方法,把圖片資訊物件,從pics陣列中移除
this.addForm.pics.splice(i, 1)
},
③圖片預覽
<!-- 圖片預覽 -->
<el-dialog title="圖片預覽" :visible.sync="previewDialogVisible" width="50%">
<img :src="previewPath" alt class="previewImg" />
</el-dialog>
// [Add.vue -> data]
previewPath: '',
previewDialogVisible: false
// [Add.vue -> methods]
// 處理圖片預覽
handlePreview(file) {
this.previewPath = file.response.data.url
this.previewDialogVisible = true
}
7、富文字編輯器
<!-- [Add.vue] -->
<el-tab-pane label="商品內容" name="4">
<!-- 富文字編輯器 -->
<quill-editor v-model="addForm.goods_introduce"></quill-editor>
<el-button type="primary" class="btnAdd" @click="add">新增商品</el-button>
</el-tab-pane>
/* [assets/css/global.css] */
.ql-editor{
min-height: 300px;
}
8、新增商品
表單預校驗,校驗通過發起請求
①預校驗
// [Add.vue -> methods]
// 新增商品
async add() {
// 預校驗
this.$refs.addFormRulesRef.validate((valid) => {
if (!valid) return this.$message.error('請填寫必要的表單項')
})
// ......
}
②深拷貝
級聯選擇器要求陣列,請求要求字串---->深拷貝
// [Add.vue -> methods]
// 新增商品
async add() {
// ......
// 執行新增的業務邏輯
// 深拷貝 lodash this.addForm雙向繫結級聯選擇器會報錯
const form = _.cloneDeep(this.addForm)
form.goods_cat = form.goods_cat.join(',')
// ......
}
③商品引數(動態引數+靜態屬性)
// [Add.vue -> methods]
// 新增商品
async add() {
// ......
// 處理動態引數
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
// ......
}
④發起請求
// [Add.vue -> methods]
// 新增商品
async add() {
// ......
// 發起請求
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')
}