欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

el-table動(dòng)態(tài)渲染列、可編輯單元格、虛擬無(wú)縫滾動(dòng)的實(shí)現(xiàn)

 更新時(shí)間:2023年12月08日 09:52:57   作者:heroboyluck  
vue對(duì)數(shù)據(jù)處理很常見(jiàn),本文主要介紹了對(duì)el-table組件二次封裝,包括對(duì)el-table的動(dòng)態(tài)渲染、單元格編輯;對(duì)于無(wú)縫滾動(dòng)的實(shí)現(xiàn),優(yōu)化大數(shù)據(jù)量下的頁(yè)面卡頓問(wèn)題,感興趣的可以了解一下

針對(duì)日常開(kāi)發(fā)的組件二次封裝、方案設(shè)計(jì)實(shí)現(xiàn)。包括對(duì)el-table的動(dòng)態(tài)渲染、單元格編輯;對(duì)于無(wú)縫滾動(dòng)的實(shí)現(xiàn),優(yōu)化大數(shù)據(jù)量下的頁(yè)面卡頓問(wèn)題。

1. el-table實(shí)現(xiàn)動(dòng)態(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>

表格比較長(zhǎng)時(shí),需要些好多的el-table-column;所以想通過(guò)動(dòng)態(tài)渲染的方式循環(huán)渲染出列項(xiàng)。

官方給出的formatter格式化列項(xiàng)輸出的方法只能格式化文本。無(wú)法渲染VNode。

嘗試通過(guò)v-html綁定,報(bào)錯(cuò)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>

解決辦法,通過(guò)render方法提供CreateElement函數(shù)。新創(chuàng)建一個(gè)組件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>

在渲染表格時(shí)調(diào)用,主要在于需要給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的語(yǔ)法,可以直接書(shū)寫。

2. el-table實(shí)現(xiàn)單元格的編輯

實(shí)現(xiàn)單元格的編輯,實(shí)現(xiàn)編輯組件EditCell.vue

邏輯的核心點(diǎn):

  • 非編輯狀態(tài)下,展示當(dāng)前列項(xiàng)值,通過(guò)點(diǎn)擊事件,單元格進(jìn)入可編輯狀態(tài)。并可通過(guò)this.$refs.input.focus()聚焦

  • 數(shù)據(jù)el-input主要在于處理完成輸入、enter鍵后完成編輯狀態(tài)。

  • 當(dāng)完成編輯時(shí),如果傳入了校驗(yàn)函數(shù)。則需調(diào)用函數(shù)進(jìn)行校驗(yàn)。并通過(guò)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>

如果要實(shí)現(xiàn)整行row的編輯,可給每一行數(shù)據(jù)追加屬性editable,整合編輯時(shí)更改屬性,切換為編輯狀態(tài)。

切入編輯狀態(tài)el-input本來(lái)想通過(guò)autofocus獲取焦點(diǎn)的。但沒(méi)有用,使用了ref組件內(nèi)部的方法。

到此這篇關(guān)于el-table動(dòng)態(tài)渲染列、可編輯單元格、虛擬無(wú)縫滾動(dòng)的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)el-table動(dòng)態(tài)渲染列、可編輯單元格、虛擬無(wú)縫滾動(dòng)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

3. 實(shí)現(xiàn)虛擬無(wú)縫滾動(dòng)seamlessScroll

使用過(guò)vue-seamless-scroll,可實(shí)現(xiàn)數(shù)據(jù)的無(wú)縫滾動(dòng)。但當(dāng)數(shù)據(jù)量超過(guò)大幾千時(shí),頁(yè)面就會(huì)變的很卡。通過(guò)看源代碼實(shí)現(xiàn),加入5000的數(shù)據(jù)量,需要渲染10000個(gè)DOM節(jié)點(diǎn)。

通過(guò)之前虛擬列表的思想,實(shí)現(xiàn)一個(gè)虛擬無(wú)縫滾動(dòng)組件

實(shí)現(xiàn)滾動(dòng)的主要API

  • transform:translate(0px,0px),在水平、垂直方向上進(jìn)行平移數(shù)據(jù)列表

  • window.requestAnimationFrame(()=>{}) 在瀏覽器下次重繪時(shí)調(diào)用回調(diào)函數(shù),通常為60次/s

實(shí)現(xiàn)的主要邏輯:

  • 組件掛載或者數(shù)據(jù)data變化時(shí)進(jìn)行數(shù)據(jù)初始化init()

  • init方法用于調(diào)用數(shù)據(jù)切割滾動(dòng)方法。其中一個(gè)參數(shù)virtual用于顯示控制如果數(shù)據(jù)量不大時(shí),就沒(méi)必要虛擬滾動(dòng)了。

  • move方法中,通過(guò)每一幀的渲染更新,回調(diào)函數(shù)處理this.translateY -= this.speed平移數(shù)據(jù)列表。

  • splitData中則處理數(shù)據(jù)切割,判斷如果不需要虛擬滾動(dòng)時(shí),則加載展示所有的數(shù)據(jù)。

  • 隨后監(jiān)聽(tīng)了translateY的變化,用于處理虛擬列表的滾動(dòng)分頁(yè)邏輯

      /**
       * 如果平移的距離大于分頁(yè)*每項(xiàng)的長(zhǎng)度,進(jìn)行數(shù)據(jù)滾動(dòng)重置
       **/
      handleDataScorll() {
        if (
          Math.abs(this.translateY) <
          this.pageOptions.pageSize * this.itemWidth
        ) {
          return;
        }
        // this.stop();
        // 第一頁(yè)已滾動(dòng)完成
        if (this.virtual) {
          this.splitData();
        }
        this.translateY = 0;
      },
    

核心的JS邏輯,實(shí)現(xiàn)的相關(guān)方法。

export default {
  // ...
  mounted() {
    // 復(fù)制數(shù)據(jù),數(shù)據(jù)倉(cāng)
    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) {
        // 非虛擬列表管滾動(dòng),則直接展示所有數(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í),才調(diào)換數(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)聽(tīng)滾動(dòng)的距離
     */
    handleDataScorll() {
      if (
        Math.abs(this.translateY) <
        this.pageOptions.pageSize * this.itemWidth
      ) {
        return;
      }
      // this.stop();
      // 第一頁(yè)已滾動(dòng)完成
      if (this.virtual) {
        this.splitData();
      }
      this.translateY = 0;
    },
    stop() {
      if (this.animationFrame) {
        cancelAnimationFrame(this.animationFrame);
      }
    }
  },
};

示例中僅實(shí)現(xiàn)豎向滾動(dòng),橫向滾動(dòng)后續(xù)會(huì)追加props屬性mode進(jìn)行邏輯處理。

4. 通過(guò)el-select實(shí)現(xiàn)聯(lián)級(jí)選擇

Element提供的Cascader,但設(shè)計(jì)師可能需要的是并排的多個(gè)下拉,進(jìn)行控制。

主要的實(shí)現(xiàn)邏輯:

  • 通過(guò)level指定聯(lián)動(dòng)選擇的層級(jí)數(shù)量。通過(guò)循環(huán)渲染出el-select,

  • 還有最關(guān)鍵的實(shí)現(xiàn)分級(jí)數(shù)據(jù), 從data中分級(jí)出每一級(jí)level數(shù)據(jù)。視圖中則通過(guò)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為層級(jí)深度長(zhǎng)度的數(shù)組,這樣才能渲染出正確數(shù)量的el-select

  • 每一層級(jí)的事件change通過(guò)index來(lái)更新選中的數(shù)據(jù)selelctData

<template>
  <div class="cascade-select-city">
    <el-select
      placeholder="請(qǐng)選擇"
      v-for="(val, index) in selectedData"
      :key="index"
      :value="selectedData[index]"
      @change="handleSelect($event, index)"
    >
      <el-option value="">請(qǐng)選擇</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: {
    /**
     * 用于自定義級(jí)聯(lián)數(shù)據(jù)
     */
    data: {
      type: Array,
      default: () => []
    },
    /**
     * 聯(lián)動(dòng)層級(jí)數(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: {
    /**
     * 處理層級(jí)數(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)動(dòng)的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>

組件僅實(shí)現(xiàn)了data為靜態(tài)數(shù)據(jù)時(shí)的邏輯處理,如果數(shù)據(jù)是動(dòng)態(tài)的呢,比如異步加載聯(lián)動(dòng)數(shù)據(jù)。

npm-虛擬無(wú)縫滾動(dòng)組件seamless-scroll

npm-element-tabl封裝

npm-lazy-load el-select 下拉懶加載

到此這篇關(guān)于el-table動(dòng)態(tài)渲染列、可編輯單元格、虛擬無(wú)縫滾動(dòng)的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)el-table動(dòng)態(tài)渲染列、可編輯單元格、虛擬無(wú)縫滾動(dòng)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論