el-table動態(tài)渲染列、可編輯單元格、虛擬無縫滾動的實現(xiàn)
針對日常開發(fā)的組件二次封裝、方案設計實現(xiàn)。包括對el-table的動態(tài)渲染、單元格編輯;對于無縫滾動的實現(xiàn),優(yōu)化大數(shù)據(jù)量下的頁面卡頓問題。
1. el-table實現(xiàn)動態(tài)渲染列
常規(guī)使用el-table
<template>
<el-table
ref="multipleTable"
:data="data"
>
<el-table-column prop="family_name" label="姓名" align="center">
</el-table-column>
<el-table-column label="操作" align="center">
<template slot-scope="scope">
<el-button
@click="handleEdit(scope.row)"
type="text"
size="small"
>用戶信息</el-button
>
</template>
</el-table-column>
</el-table>
</template>
<script>
export default {
data(){
return {
data:[]
}
},
methods:{
handleEdit(){}
}
}
</script>
表格比較長時,需要些好多的el-table-column;所以想通過動態(tài)渲染的方式循環(huán)渲染出列項。
官方給出的formatter格式化列項輸出的方法只能格式化文本。無法渲染VNode。
嘗試通過v-html綁定,報錯h is not a function
// ...
<el-table-column label="操作" align="center">
<template slot-scope="scope">
<div v-html="item.render(scope)"></div>
</template>
</el-table-column>
解決辦法,通過render方法提供CreateElement函數(shù)。新創(chuàng)建一個組件RenderColumn
RenderColumn.vue
<script>
export default {
props:{
render:{
type:Function,
default:()=>()=>{}
},
scope:{
type:Object,
default:()=>{}
}
},
render(h){
const { row, column, $index } = this.scope
return this.render(h,row,column,$index)
}
}
</script>
在渲染表格時調用,主要在于需要給render方法傳入CreateElement方法。
<template>
<el-table
ref="multipleTable"
:data="data"
>
<el-table-column v-for="item in columns" :label="item.lable" :prop="item.prop">
<template slot-scope="scope">
<render-column v-if="item.render" :render="item.render" :scope="scope" />
<span v-else>{{scope.row[item.prop]}}</span>
</template>
</el-table-column>
</el-table>
</template>
<script>
export default {
data(){
let $this = this
return {
data:[],
columns:[
{
label:'姓名',
prop:'name'
},
{
label:'操作',
render(h,row,column){
return <el-button
onClick={$this.handleEdit(row)}
type="text"
size="small"
>用戶信息</el-button>
}
}
]
}
},
methods:{
handleEdit(){}
}
}
</script>
vue-cli腳手架已經(jīng)繼承了JSX的語法,可以直接書寫。
2. el-table實現(xiàn)單元格的編輯
實現(xiàn)單元格的編輯,實現(xiàn)編輯組件EditCell.vue
邏輯的核心點:
非編輯狀態(tài)下,展示當前列項值,通過點擊事件,單元格進入可編輯狀態(tài)。并可通過
this.$refs.input.focus()聚焦數(shù)據(jù)
el-input主要在于處理完成輸入、enter鍵后完成編輯狀態(tài)。當完成編輯時,如果傳入了校驗函數(shù)。則需調用函數(shù)進行校驗。并通過
el-popover展示。
<template>
<div class="edit-cell">
<el-popover :value="validateMsg !== ''" trigger="manual">
<div slot="reference">
<span v-if="!editable" @click="handleEditable"
>{{ editValue }}
<i class="el-icon-edit"></i>
</span>
<el-input
ref="input"
autofocus
v-else
v-model="editValue"
@change="handleEditable"
@blur="handleEditable"
/>
</div>
<span style="color: #f5222d">{{ validateMsg }}</span>
</el-popover>
</div>
</template>
<script>
export default {
name: "edit-cell",
props: {
value: String,
validator: {
type: Function,
default: () => null
}
},
data() {
return {
editValue: "",
editable: false,
validateMsg: ""
};
},
mounted() {
this.editValue = this.value;
},
methods: {
handleEditable() {
if (this.editable && typeof this.validator === "function") {
const err = this.validator(this.editValue);
if (err) {
this.validateMsg = err;
return;
}
this.validateMsg = "";
}
this.editable = !this.editable;
if (this.editable) {
this.$nextTick(() => {
this.$refs.input.focus();
});
}
this.$emit("change", this.editValue);
}
}
};
</script>
如果要實現(xiàn)整行row的編輯,可給每一行數(shù)據(jù)追加屬性editable,整合編輯時更改屬性,切換為編輯狀態(tài)。
切入編輯狀態(tài)el-input本來想通過autofocus獲取焦點的。但沒有用,使用了ref組件內部的方法。
到此這篇關于el-table動態(tài)渲染列、可編輯單元格、虛擬無縫滾動的實現(xiàn)的文章就介紹到這了,更多相關el-table動態(tài)渲染列、可編輯單元格、虛擬無縫滾動內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
3. 實現(xiàn)虛擬無縫滾動seamlessScroll
使用過vue-seamless-scroll,可實現(xiàn)數(shù)據(jù)的無縫滾動。但當數(shù)據(jù)量超過大幾千時,頁面就會變的很卡。通過看源代碼實現(xiàn),加入5000的數(shù)據(jù)量,需要渲染10000個DOM節(jié)點。
通過之前虛擬列表的思想,實現(xiàn)一個虛擬無縫滾動組件
實現(xiàn)滾動的主要API
transform:translate(0px,0px),在水平、垂直方向上進行平移數(shù)據(jù)列表window.requestAnimationFrame(()=>{})在瀏覽器下次重繪時調用回調函數(shù),通常為60次/s
實現(xiàn)的主要邏輯:
組件掛載或者數(shù)據(jù)
data變化時進行數(shù)據(jù)初始化init()init方法用于調用數(shù)據(jù)切割滾動方法。其中一個參數(shù)virtual用于顯示控制如果數(shù)據(jù)量不大時,就沒必要虛擬滾動了。在
move方法中,通過每一幀的渲染更新,回調函數(shù)處理this.translateY -= this.speed平移數(shù)據(jù)列表。在
splitData中則處理數(shù)據(jù)切割,判斷如果不需要虛擬滾動時,則加載展示所有的數(shù)據(jù)。隨后監(jiān)聽了
translateY的變化,用于處理虛擬列表的滾動分頁邏輯/** * 如果平移的距離大于分頁*每項的長度,進行數(shù)據(jù)滾動重置 **/ handleDataScorll() { if ( Math.abs(this.translateY) < this.pageOptions.pageSize * this.itemWidth ) { return; } // this.stop(); // 第一頁已滾動完成 if (this.virtual) { this.splitData(); } this.translateY = 0; },
核心的JS邏輯,實現(xiàn)的相關方法。
export default {
// ...
mounted() {
// 復制數(shù)據(jù),數(shù)據(jù)倉
this.copyData = [...this.data];
// 切割數(shù)據(jù)
this.init();
},
computed: {
boxStyle() {
return {
transform: `translate(0, ${this.translateY}px )`,
};
},
total() {
return this.data.length;
},
},
watch: {
data(newData) {
this.copyData = [...newData];
this.init();
},
translateY() {
this.handleDataScorll();
},
},
methods: {
init() {
if (!this.virtual) {
// 非虛擬列表管滾動,則直接展示所有數(shù)據(jù)
this.pageOptions.pageSize = this.total;
}
if (this.total > 0) {
this.splitData();
this.move();
}
},
move() {
this.stop();
this.animationFrame = requestAnimationFrame(() => {
if (this.total > 0) {
this.translateY -= this.speed;
}
this.move();
});
},
splitData() {
if (!this.virtual) {
this.preData = [...this.copyData];
this.nextData = [...this.copyData];
return;
}
// 只有在虛擬列表時,才調換數(shù)據(jù)位置
this.copyData = [...this.copyData, ...this.preData];
// pre
this.preData = this.copyData.splice(0, this.pageOptions.pageSize);
// next
this.nextData = this.copyData.slice(0, this.pageOptions.pageSize);
},
/**
* 監(jiān)聽滾動的距離
*/
handleDataScorll() {
if (
Math.abs(this.translateY) <
this.pageOptions.pageSize * this.itemWidth
) {
return;
}
// this.stop();
// 第一頁已滾動完成
if (this.virtual) {
this.splitData();
}
this.translateY = 0;
},
stop() {
if (this.animationFrame) {
cancelAnimationFrame(this.animationFrame);
}
}
},
};
示例中僅實現(xiàn)豎向滾動,橫向滾動后續(xù)會追加props屬性mode進行邏輯處理。
4. 通過el-select實現(xiàn)聯(lián)級選擇
Element提供的Cascader,但設計師可能需要的是并排的多個下拉,進行控制。
主要的實現(xiàn)邏輯:
通過level指定聯(lián)動選擇的層級數(shù)量。通過循環(huán)渲染出
el-select,還有最關鍵的實現(xiàn)分級數(shù)據(jù), 從data中分級出每一級level數(shù)據(jù)。視圖中則通過
optionsData[index]獲取數(shù)據(jù)
optionsData: function () {
let arr = [[...this.data]]
for (let id of this.selectedData) {
if (!id) {
arr.push([])
break
}
let data = arr[arr.length - 1].find((item) => item.id === id)
if (!data) {
arr.push([])
break
}
arr.push(data.children || [])
}
return arr
}
最重要的是保證
selectedData為層級深度長度的數(shù)組,這樣才能渲染出正確數(shù)量的el-select每一層級的事件
change通過index來更新選中的數(shù)據(jù)selelctData
<template>
<div class="cascade-select-city">
<el-select
placeholder="請選擇"
v-for="(val, index) in selectedData"
:key="index"
:value="selectedData[index]"
@change="handleSelect($event, index)"
>
<el-option value="">請選擇</el-option>
<el-option
v-for="item in optionsData[index]"
:key="item.id"
:label="item.name"
:value="item.name"
/>
</el-select>
</div>
</template>
<script>
export default {
name: 'cascade-select',
props: {
/**
* 用于自定義級聯(lián)數(shù)據(jù)
*/
data: {
type: Array,
default: () => []
},
/**
* 聯(lián)動層級數(shù)量
*/
level: {
type: Number,
default: 1
},
/**
* 綁定數(shù)據(jù)
*/
value: {
type: Array,
default: () => []
}
},
data () {
return {
selectedData: new Array(this.level).fill('')
}
},
mounted () {
},
watch: {
value (val, oldVal) {
if (JSON.stringify([val]) !== JSON.stringify([this.selectedData])) {
//
this.selectedData = [...val]
}
}
},
computed: {
/**
* 處理層級數(shù)據(jù)
*/
optionsData: function () {
let arr = [[...this.data]]
for (let id of this.selectedData) {
if (!id) {
arr.push([])
break
}
let data = arr[arr.length - 1].find((item) => item.AreaId === id)
if (!data) {
arr.push([])
break
}
arr.push(data.children || [])
}
return arr
}
},
methods: {
/**
* 處理聯(lián)動的select
*/
handleSelect (selected, level) {
// 更新值
this.selectedData = this.selectedData.map((val, index) => {
if (index < level) {
return val
}
return index === level ? selected : ''
})
this.$emit('change', this.selectedData)
}
}
}
</script>
組件僅實現(xiàn)了data為靜態(tài)數(shù)據(jù)時的邏輯處理,如果數(shù)據(jù)是動態(tài)的呢,比如異步加載聯(lián)動數(shù)據(jù)。
到此這篇關于el-table動態(tài)渲染列、可編輯單元格、虛擬無縫滾動的實現(xiàn)的文章就介紹到這了,更多相關el-table動態(tài)渲染列、可編輯單元格、虛擬無縫滾動內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
利用hasOwnProperty給數(shù)組去重的面試題分享
obj.hasOwnProperty(attr) 判斷是否是原型中的屬性,false就是原型中的屬性,下面這篇文章主要給大家介紹了一道利用hasOwnProperty給數(shù)組去重的面試題,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下2018-11-11
JS實現(xiàn)的另類手風琴效果網(wǎng)頁內容切換代碼
這篇文章主要介紹了JS實現(xiàn)的另類手風琴效果網(wǎng)頁內容切換代碼,通過JavaScript響應鼠標事件動態(tài)操作頁面元素樣式屬性實現(xiàn)手風琴效果,具有一定參考借鑒價值,需要的朋友可以參考下2015-09-09

