此demo選用的vue2.x版本
看完你將收獲以下幾點(diǎn)技能:
- 快速創(chuàng)建vue項(xiàng)目
- 理解vue常用指令的使用場(chǎng)景
- 網(wǎng)站快速成型工具Element-ui使用
- 項(xiàng)目中增刪改查的具體應(yīng)用
效果圖
技術(shù)棧
vue2.x + Element-ui + sass + esLint + standard
構(gòu)建工具選擇
如你遇到包下載慢、依賴(lài)不同導(dǎo)致各種bug等等(因?yàn)閚pm鏡像地址在國(guó)外所以訪問(wèn)會(huì)慢有的時(shí)候還訪問(wèn)不到),可選用淘寶鏡像地址(淘寶鏡像同步頻率目前為10分鐘一次以保證盡量與官方服務(wù)同步)或者pnpm,
pnpm是高性能的npm,pnpm節(jié)省磁盤(pán)空間,安裝速度快;通過(guò)內(nèi)容可尋址存儲(chǔ)(CAS)、符號(hào)鏈接(Symbolic Link)、硬鏈接(Hard Link)等管理依賴(lài)包。
設(shè)置淘寶鏡像地址
// 淘寶鏡像新地址舊地址
https://registry.npm.taobao.org // 舊
https://registry.npmmirror.com // 新
// 永久使用
npm config set registry https://registry.npmmirror.com
// 使用淘寶鏡像并把npm設(shè)置為cnpm
npm install -g cnpm --registry=https://registry.npm.npmmirror.org
// 查看是否設(shè)置成功
npm get registry
換回npm官網(wǎng)地址
如果淘寶鏡像影響你發(fā)布模塊可這樣換回去
npm config set registry https://registry.npmjs.org
安裝pnpm
npm install -g pnpm
// 或
cnpm install -g pnpm
一.安裝vue
在安裝之前先確保安裝了node環(huán)境, 如果沒(méi)有安裝,去官網(wǎng)最新穩(wěn)定版下載nodejs
全局安裝vue-cli
一鍵生成工程化的vue項(xiàng)目
cnpm install -g @vue/cli
# 或者
yarn global add @vue/cli
查看vue-cli版本
vue -V // @vue/cli 5.0.8 vue-^2.6.14
創(chuàng)建vue項(xiàng)目
vue create vue2-demo
// 或者
mkdir vue2-demo && cd vue2-demo // 創(chuàng)建vue2-demo文件夾并進(jìn)入目錄
vue create . // 在當(dāng)前創(chuàng)建vue項(xiàng)目
接下來(lái)會(huì)出現(xiàn)選擇以前的配置項(xiàng)還是vue默認(rèn)創(chuàng)建的項(xiàng)目,還是手動(dòng)選擇,
選擇Manually select features(手動(dòng)安裝),會(huì)進(jìn)入下一步操作
用空格和上下箭頭選擇配置項(xiàng)
CSS Pre-processors // CSS 預(yù)處理器
Linter / Formatter // 代碼風(fēng)格檢查和格式化(選擇保存和提交時(shí)校驗(yàn))
選擇standard編碼規(guī)范
Sass/SCSS (with dart-sass) // 如果不想安裝node-sass選擇dart-sass
查看standardjs編碼規(guī)范
二.安裝Element-ui
cnpm i element-ui -S
三.使用element-ui布局頁(yè)面
第一步先在main.js 引入ui
完整引入
import Vue from 'vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import App from './App.vue';
Vue.use(ElementUI);
new Vue({
el: '#app',
render: h => h(App)
});
兩種引入方式: 完整引入和按需引入,建議選用按需引入,具體操作見(jiàn)官網(wǎng)
流程:官網(wǎng)-> 組件 -> 快速上手
element官網(wǎng)
第二步:布局頁(yè)面
找到Container 布局容器模塊,選擇第一個(gè)模版 由header和main組成的模塊,也就是分為標(biāo)題和主內(nèi)容部分
<el-container>
<el-header>Header</el-header>
<el-main>Main</el-main>
</el-container>
按模塊添加如下代碼:
<el-container>
<el-header>vue2.x增刪改查part01</el-header>
<el-container>
<el-main>
<el-form :inline="true" :model="formInline" class="demo-form-inline">
<el-form-item>
<el-input placeholder="請(qǐng)輸入用戶(hù)名" v-model="formInline.username" clearable>
</el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search">查詢(xún)</el-button>
<el-button type="success" @click="show">添加</el-button>
<el-button type="danger">批量刪除</el-button>
</el-form-item>
</el-form>
<el-table v-if="tableData.length > 0" :data="tableData" border style="width: 100%">
<el-table-column type="selection" width="40">
</el-table-column>
<el-table-column fixed prop="date" label="日期" width="150">
</el-table-column>
<el-table-column prop="name" label="姓名" width="120">
</el-table-column>
<el-table-column prop="province" label="省份" width="120">
</el-table-column>
<el-table-column prop="city" label="市區(qū)" width="120">
</el-table-column>
<el-table-column prop="address" label="地址" width="300">
</el-table-column>
<el-table-column prop="zip" label="郵編" width="120">
</el-table-column>
<el-table-column fixed="right" label="操作">
<template slot-scope="scope">
<el-button
@click="handleClick(scope.row)"
type="primary"
size="mini"
>查看</el-button
>
<el-button type="success" size="mini">編輯</el-button>
<el-button type="danger" size="mini">刪除</el-button>
</template>
</el-table-column>
</el-table>
<div class="nodata" v-else>無(wú)數(shù)據(jù)...</div>
</el-main>
</el-container>
</el-container>
彈出框模版代碼
<!-- dialog start -->
<el-dialog
title="默認(rèn)彈層標(biāo)題"
:visible.sync="showDialog"
custom-class="mydialog"
@close="close"
>
<div slot="title" align="left">添加信息</div>
<el-form
:model="addQuery"
:inline="true"
label-position="right"
label-width="80px"
>
<el-form-item label="用戶(hù)名">
<el-input v-model="addQuery.username" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="選擇日期">
<el-date-picker
v-model="addQuery.date"
type="date"
style="width:90%"
placeholder="選擇日期"
>
</el-date-picker>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="close">取 消</el-button>
<el-button type="primary" @click="add">確 定</el-button>
</div>
</el-dialog>
<!-- dialog end! -->
頁(yè)面js初始數(shù)據(jù)
data () {
return {
idx: 1, // 初始化id 為了使用本地?cái)?shù)據(jù)
editId: 0, // 要編輯的id
showDialog: false, // 彈出層開(kāi)關(guān)
addQuery: { // 添加字段
username: '',
date: ''
},
formInline: { // 查詢(xún)字段
username: ''
},
tableData: [
{
id: 1,
date: '2016-05-02',
name: '王小虎1',
province: '上海',
city: '普陀區(qū)',
address: '上海市普陀區(qū)金沙江路 1518 弄',
zip: 200333
},
{
id: 2,
date: '2016-05-04',
name: '王小虎2',
province: '上海',
city: '普陀區(qū)',
address: '上海市普陀區(qū)金沙江路 1517 弄',
zip: 200333
},
{
id: 3,
date: '2016-05-01',
name: '王小虎3',
province: '上海',
city: '普陀區(qū)',
address: '上海市普陀區(qū)金沙江路 1519 弄',
zip: 200333
},
{
id: 4,
date: '2016-05-03',
name: '王小虎4',
province: '上海',
city: '普陀區(qū)',
address: '上海市普陀區(qū)金沙江路 1516 弄',
zip: 200333
}
]
}
},
methods: {
handleClick (row) {
console.log(row) // 查看 暫時(shí)不做什么功能
}
}
備注:如果table出不來(lái),一片空白,原因是element-ui版本過(guò)高,在package里修改版本后 element-ui版本,cnpm install即可
四.添加-增/刪/改/查 邏輯
查詢(xún)
<el-input placeholder="請(qǐng)輸入用戶(hù)名" v-model.trim="formInline.username" clearable></el-input>
<el-button type="primary" icon="el-icon-search" @click="search">查詢(xún)</el-button>
// js-code
search () {
/*
第一步:先拿到input輸入的內(nèi)容
第二步: 遍歷數(shù)組找到元素filter
第三步:原數(shù)組賦值-更新視圖
*/
const userName = this.formInline.username
if (userName === '') {
alert('請(qǐng)輸入查詢(xún)內(nèi)容哦') // 暫時(shí)用alert 哦~,可以用element自帶的漂亮框
return
}
const tableData = JSON.parse(localStorage.getItem('tableData'))
this.tableData = tableData.filter(item => item.name === userName)
}
注意:因?yàn)槭潜镜財(cái)?shù)據(jù),當(dāng)查詢(xún)條件有一個(gè)成立,不刷新頁(yè)面的情況,再次查詢(xún)會(huì)出現(xiàn)無(wú)數(shù)據(jù),原因是:
假如:第一次查詢(xún)name為王小虎1,把過(guò)濾的結(jié)果賦值給tableData,那么,
此時(shí)tableData里就只有name為王小虎1的這條數(shù)據(jù);
再次查詢(xún),即從最新的tableData里查詢(xún),查詢(xún)name為王小虎2的,顯
然找不到,所以也就會(huì)出現(xiàn)無(wú)數(shù)據(jù)情況。
解決辦法:因?yàn)槭潜镜財(cái)?shù)據(jù)庫(kù),那么我們可以在頁(yè)面掛載成功后,把tableData放到本地緩存一份,增加或者刪除的時(shí)候更新本地緩存,查詢(xún)的時(shí)候從本地緩存里查詢(xún),即可解決這個(gè)問(wèn)題。
新增localStoreSetItem函數(shù)
localStoreSetItem () {
localStorage.setItem('tableData', JSON.stringify(this.tableData))
}
mounted () {
this.idx = this.tableData.length // 本地?cái)?shù)據(jù)生成id,用接口方式不需要這行代碼哦
this.localStoreSetItem()
},
添加邏輯
<el-button type="primary" @click="add">確 定</el-button>
add () {
/*
第一步:拿到彈出層輸入框內(nèi)容
定義日期格式化函數(shù):formatDate 轉(zhuǎn)換格式
第二步:追加到tableData數(shù)組中
定義插入對(duì)象格式
第三步:給tableData賦值 ->更新視圖
第四步:彈出層數(shù)據(jù)數(shù)據(jù)恢復(fù)默認(rèn),關(guān)閉彈出層后把屬性設(shè)置為空 新增close
*/
const { username, date } = this.addQuery
const newDate = this.formatDate(date)
const obj = {
date: newDate,
name: username,
province: '上海',
city: '普陀區(qū)',
address: '上海市普陀區(qū)金沙江路 1518 弄',
zip: 200333
}
this.tableData.unshift(obj)
this.showDialog = false
},
close () {
this.showDialog = false
this.addQuery.name = ''
this.addQuery.date = ''
},
}
刪除邏輯
// 模版
<el-button type="danger" size="mini" @click="del(scope.row.id)">刪除</el-button>
// js
del (id) {
// 兩種方法:filter,和splice 推薦splice
// this.tableData = this.tableData.filter((e) => e.id !== id)
// 先查找當(dāng)前要?jiǎng)h除的id在數(shù)組的位置
const index = this.tableData.findIndex((item) => item.id === id)
// 從當(dāng)前位置開(kāi)始刪除1條內(nèi)容
this.tableData.splice(index, 1)
// 更新緩存中的tableData數(shù)據(jù)
this.localStoreSetItem()
}
注意:刪除的兩種方法;注意更新本地緩存數(shù)據(jù),不然有bug哦,刪除后的元素還能被搜索到哦
批量刪除
需要在el-table組件上綁定事件函數(shù),@selection-change=“自定義函數(shù)”,可以拿到選中的元素集合數(shù)組展示
// 模版
<el-table
v-if="tableData.length > 0"
@selection-change="handleSelectionTable"
:data="tableData"
border
style="width: 100%"
>
// js
handleSelectionTable (val) {
this.selectionTableArr = val
},
delMore () {
/* 一.如果是后臺(tái)接口只需要傳遞[id1,id],那我們直接把選中的id拿出來(lái)即可
兩種方法:forEach,reduce
*/
console.time('forEach')
const ids = []
this.selectionTableArr.forEach(item => {
ids.push(item.id)
})
console.timeEnd('forEach') // forEach: 0.02099609375 ms
// reduce效率最高
console.time('reduce')
const ids1 = this.selectionTableArr.reduce((arr, item) => {
arr.push(item.id)
return arr
}, [])
console.timeEnd('reduce') // reduce: 0.009033203125 ms
console.log(ids1)
/* 二. 以上是給接口的,那么現(xiàn)在處理本地的批量刪除
第一步:循環(huán)刪除 -> 遞歸 do-while; 遞歸條件已選擇的數(shù)組len小于0的時(shí)候停止
第二步:需要遞歸處理的事情,也就是while放的代碼:先查找已選中的id在原數(shù)組的位置,然后splice刪除1項(xiàng)
第三步:更新本地緩存
*/
let len = this.selectionTableArr.length
do {
const index = this.tableData.findIndex(item => item.id === this.selectionTableArr[len - 1].id)
this.tableData.splice(index, 1)
len--
// 剛更新本地緩存
this.localStoreSetItem()
} while (len > 0)
},
修改邏輯
因?yàn)樾薷倪壿嬏幚硗陻?shù)據(jù)回填后,走的還是添加的邏輯,所以添加代碼修改為
show () {
this.showDialog = true
this.editId = 0
},
edit (row) {
/*
分析:把當(dāng)前要編輯的row拿到;然后賦值給彈出層表單model的addQuery對(duì)象,addQuery對(duì)象更新input的v-model值更新
第一步:拿到當(dāng)前點(diǎn)擊的row對(duì)象
第二步:給addQuery對(duì)象的屬性賦值 for in 或者 深拷貝
第三步:點(diǎn)擊保存后:1.如果是走的接口,那么會(huì)和添加是一樣的邏輯
2.如果更新本地緩存,那么先找到當(dāng)前id所在數(shù)組的位置
接著,用splice(index, 1, 新的內(nèi)容對(duì)象) // 刪除一條用新的內(nèi)容替換
第四步:更新最新緩存數(shù)據(jù)tableData
*/
this.showDialog = true
for (const k in row) {
this.addQuery[k] = row[k]
}
this.editId = row.id
this.showDialog = true
},
add (id) {
/*
第一步:拿到彈出層輸入框內(nèi)容
定義日期格式化函數(shù):formatDate 轉(zhuǎn)換格式
第二步:追加到tableData數(shù)組中
定義插入對(duì)象格式
第三步:給tableData賦值 更新視圖
第四步:彈出層數(shù)據(jù)數(shù)據(jù)恢復(fù)默認(rèn),關(guān)閉彈出層,
*/
!this.showDialog && (this.showDialog = true)
const { name, date } = this.addQuery
if (name === '' && this.date === '') {
alert('請(qǐng)?zhí)顚?xiě)內(nèi)容')
return
}
// 如果有要修改的數(shù)據(jù),把之前的舊數(shù)據(jù)刪除
const index = this.tableData.findIndex(item => id === item.id)
const newDate = this.formatDate(date)
const obj = {
id: ++this.idx,
date: newDate,
name,
province: '上海',
city: '普陀區(qū)',
address: '上海市普陀區(qū)金沙江路 1518 弄',
zip: 200333
}
if (this.editId > 0) {
this.tableData.splice(index, 1, obj) // 如果是修改元素順序不變
this.editId = 0
} else {
this.tableData.unshift(obj) // 如果是新添加第一條出現(xiàn)最上面
}
this.localStoreSetItem() // 不管是添加還是修改都要更新本地緩存
this.close()
},
五. 總結(jié)
1.添加或者修改數(shù)據(jù)后再次打開(kāi)彈出層記得清空上一次的記錄狀態(tài)
2.使用本地?cái)?shù)據(jù)和真實(shí)項(xiàng)目中的接口操作數(shù)據(jù)有很多地方變化,一定要注意之間的關(guān)系。