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

如何巧用Vue.extend繼承組件實現(xiàn)el-table雙擊可編輯(不使用v-if、v-else)

 更新時間:2022年06月14日 10:31:31   作者:水冗水孚  
這篇文章主要給大家介紹了關于如何巧用Vue.extend繼承組件實現(xiàn)el-table雙擊可編輯的相關資料,不使用v-if、v-else,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下

問題描述

有一個簡單的表格,產(chǎn)品要求實現(xiàn)雙擊可編輯

看了一下網(wǎng)上的帖子,大多數(shù)都是搞兩部分dom,一塊是輸入框,用于編輯狀態(tài)填寫;另一塊是普通標簽,用于在不編輯顯示狀態(tài)下呈現(xiàn)單元格文字內(nèi)容。再加上一個flag標識搭配v-if和v-else去控制編輯狀態(tài)、還是顯示狀態(tài)。大致代碼如下:

  <el-table-column
    align="center"
    label="姓名"
  >
    <template slot-scope="scope">
      <!--isClick就是標識狀態(tài),狀態(tài)處于編輯時候,顯示輸入框,狀態(tài)屬于呈現(xiàn)狀態(tài)就顯示文本內(nèi)容-->
      <el-input v-if="scope.row.isClick" v-model="scope.row.name"  @blur="blurFn(scope.row)"></el-input>
      <span @click="clickCell(scope.row)" v-else>{{scope.row.name}}</span>
    </template>
  </el-table-column>

這種方式有其適用場景,但是得每個el-table-column列中都加上el-input和span以及v-if和v-else。我們嘗試一下動態(tài)添加el-input,就是點擊那個單元格,給那個單元格添加el-input讓其處于可編輯狀態(tài),然后適時移除即可。這樣的話,很多列的時候,就不用加很多個v-if和v-else啦。我們先看一下效果圖

效果圖

代碼思路

  • 第1步:給el-table綁定雙擊事件 @cell-dblclick='dblclick',再雙擊事件的回調(diào)函數(shù)中,可以得知點擊的是哪一行、那一列、那個單元格dom,以及點擊事件。dblclick(row, column, cell, event) {...},這個是餓了么官方提供的,沒啥好說的
  • 第2步:重點來嘍
    • 第2.1步:單元格雙擊事件以后,我們首先創(chuàng)建一個el-input標簽,然后把點擊的這個單元格的值,作為參數(shù)props讓這個el-input接收,這樣的話el-input就會顯示這個單元格的值了,就可以編輯了。問題一:如何創(chuàng)建一個el-input標簽? ,客官稍等,下方會解答
    • 第2.2步:把創(chuàng)建好的el-input標簽替換掉原來的單元格span標簽,這樣的話,就可以看到單元格變成了可輸入的輸入框了。問題二:如何把新創(chuàng)建的el-input標簽,替換原有的span標簽 ,客官稍等,下方會解答
    • 第2.3步,當用戶編輯完了點擊別處時候,即輸入框失去焦點的時候,再把el-input輸入框標簽移除掉,恢復默認的span標簽(當然失去焦點的時候,就要發(fā)請求修改數(shù)據(jù)了)問題三:如何移除el-input標簽,并恢復原有的span標簽,客官稍等,下方會解答
  • 這樣的話,每次雙擊搞一個input標簽用于修改,每次改完了失去焦點,就恢復默認單元格展示狀態(tài)了,功能就實現(xiàn)了

代碼思路中的三個問題解答

問題一:如何創(chuàng)建一個el-input標簽?

我們知道,如果是創(chuàng)建原生的input標簽并指定一個值,比較簡單,直接:

let input = document.createElement('input') // 創(chuàng)建一個input標簽
input.value = '孫悟空' // 給input標簽賦值
document.body.appendChild(input) // 把input標簽追加到文檔body中

不過el-input標簽不能通過上述方式創(chuàng)建,因為document.createElement()方法雖然可以創(chuàng)建出來el-input標簽,但是dom并不認識這個el-input標簽,所以頁面沒有變化。畢竟餓了么的el-input也是把input標簽做一個二次封裝的

所以,這里我們可以使用Vue.extend()方法去繼承一個組件并暴露出去,而繼承的這個組件中又有一個input標簽,所以那個需要使用,那里就可以引入并new出來一個el-input了。關于Vue.extend()的定義啥的,這里不贅述,詳情看官方文檔。筆者之前也寫過一篇Vue.extend文章,傳送門:http://www.dbjr.com.cn/article/251484.htm

首先搞一個.vue文件,用于繼承

// input.vue文件
<template>
  <div class="cell">
    <el-input
      ref="elInputRef"
      size="mini"
      v-model.trim="cellValue"
    ></el-input>
  </div>
</template>

props: {
    cellValue: {
      type: String | Number,
      default: "",
    },
}

然后定義一個data.js文件,繼承input.vue文件,并暴露

// data.js
import Vue from "vue";
import definedInput from "./input.vue";
// vue繼承這個input組件,就相當于一個構造函數(shù)了
const inputC = Vue.extend(definedInput);
// 暴露出去,哪里需要哪里引入
export default {
    inputC,
}

頁面中引入并使用

// page.vue
import extendComponents from "./threeC/data"; // 1. 引入

new extendComponents.inputC({ // 2. 實例化
    propsData: {
      // 使用propsData對象傳遞參數(shù),子組件在props中可以接收到
      cellValue: cellValue, // 傳遞單元格的值
    },
  }).$mount(cell.children[0]);// 3. 掛載

propsData對象用于給繼承的組件傳遞參數(shù),也可以傳遞一個函數(shù),從而繼承組件通過這個函數(shù)通知外部使用組件,詳情見后續(xù)完整代碼

問題二三:el-input標簽和span標簽的來回替換恢復

使用$mount方法去做來回替換,$mount可以把一個子dom元素追加到父dom元素內(nèi)部,相當于appendChild

然后這里需要有一個替換的時機,就是實例化的組件中的el-input失去焦點的時候,去通知外部使用的組件,所以可以在外部使用是,在propsData中傳遞一個函數(shù)到繼承的組件,如:

// 外部組件傳遞
new extendComponents.inputC({
    propsData: {
      cellValue: cellValue, // 傳遞單元格的值
      saveRowData: this.saveRowData, // 傳遞回調(diào)函數(shù)用于通知,繼承組件中可以觸發(fā)之
    },
}).$mount(cell.children[0]); 

saveRowData(params){
    console.log('收到繼承組件消息通知啦參數(shù)為:',params)
}
// 內(nèi)部組件失去焦點時候通知
<el-input
  ref="elInputRef"
  size="mini"
  v-model.trim="cellValue"
  @blur="blurFn"
></el-input>

props: {
    cellValue: {
      type: String | Number,
      default: "",
    },
    saveRowData: Function, // 外部,傳遞進來一個函數(shù),當這個el-input失去焦點的時候,通過此函數(shù)通知外部
}

blurFn() {
  // 失去焦點,再拋出去,通知外部
  this.saveRowData({
    cellValue: this.cellValue,
    // 其他參數(shù)
  });
},

所以當內(nèi)層失去焦點的時候,就可以通知外層去做一個替換了,就是把單元格dom重新做一個$mount掛載,就把el-input替換成了span了,為了進一步理解,這里的span我們也可以使用繼承的方式,是new實例化使用,詳情見下方完整代碼

完整代碼

目錄結構

threeC
-- data.js
-- input.vue
-- span.vue
three.vue

用于繼承的el-input組件

input.vue

<template>
  <div class="cell">
    <el-input
      ref="elInputRef"
      size="mini"
      v-model.trim="cellValue"
      @blur="blurFn"
    ></el-input>
  </div>
</template>

<script>
export default {
  props: {
    cellValue: {
      type: String | Number,
      default: "",
    },
    saveRowData: Function, // 外部,傳遞進來一個函數(shù),當這個el-input失去焦點的時候,通過此函數(shù)通知外部
    cellDom: Node, // 單元格dom
    row: Object, // 單元格所在行數(shù)據(jù)
    property: String, // 單元格的key
  },
  mounted() {
    // 用戶雙擊后,讓其處于獲取焦點的狀態(tài)
    this.$refs.elInputRef.focus();
  },
  methods: {
    blurFn() {
      // 失去焦點,再拋出去,通知外部
      this.saveRowData({
        cellValue: this.cellValue,
        cellDom: this.cellDom,
        row: this.row,
        property: this.property,
      });
    },
  },
};
</script>

<style>
.cell {
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  box-sizing: border-box;
  padding: 0 8px;
}
</style>

用于繼承的span組件

span.vue

<template>
  <span class="cell">{{ cellValue }}</span>
</template>

<script>
export default {
  props: {
    cellValue: {
      type: String | Number,
      default: "",
    },
  },
};
</script>

統(tǒng)一繼承并暴露data.js文件

import Vue from "vue";
import definedInput from "./input.vue";
import definedSpan from "./span.vue";

const inputC = Vue.extend(definedInput);
const spanC = Vue.extend(definedSpan);

export default {
    inputC,
    spanC,
}

使用繼承的three.vue組件

<template>
  <div id="app">
    <el-table
      @cell-dblclick="dblclick"
      :cell-class-name="cellClassName"
      height="480"
      :data="tableData"
      border
    >
      <el-table-column align="center" type="index" label="序號" width="50">
      </el-table-column>
      <el-table-column align="center" prop="name" label="姓名" width="100">
      </el-table-column>
      <el-table-column align="center" prop="age" label="年齡" width="100">
      </el-table-column>
      <el-table-column align="center" prop="home" label="家鄉(xiāng)">
      </el-table-column>
    </el-table>
  </div>
</template>

<script>
// 引入繼承組件對象,可取其身上的inputC構造函數(shù)、或spanC構造函數(shù)生成組件dom
import extendComponents from "./threeC/data";
export default {
  data() {
    return {
      tableData: [
        {
          name: "孫悟空",
          age: 500,
          home: "花果山水簾洞",
        },
        {
          name: "豬八戒",
          age: 88,
          home: "高老莊",
        },
        {
          name: "沙和尚",
          age: 1000,
          home: "通天河",
        },
      ],
      /**
       * 存一份舊的值,用于校驗是否發(fā)生變化,是否修改
       * */
      oldCellValue: null,
    };
  },
  methods: {
    cellClassName({ row, column, rowIndex, columnIndex }) {
      row.index = rowIndex; // 自定義指定一個索引,下方能夠用到
    },
    dblclick(row, column, cell, event) {
      // 1. 序號列單元格不允許編輯,別的列單元格可以編輯
      if (column.label == "序號") {
        this.$message({
          type: "warning",
          message: "序號列不允許編輯",
        });
        return;
      }
      // 2. 存一份舊的單元格的值
      this.oldCellValue = row[column.property];
      // 3. 然后把單元格的值,作為參數(shù)傳遞給實例化的input組件
      let cellValue = row[column.property];
      // 4. 實例化組件以后,帶著參數(shù),再掛載到對應位置
      new extendComponents.inputC({
        propsData: {
          // 使用propsData對象傳遞參數(shù),子組件在props中可以接收到
          cellValue: cellValue, // 傳遞單元格的值
          saveRowData: this.saveRowData, // 傳遞回調(diào)函數(shù)用于保存行數(shù)據(jù),組件中可以觸發(fā)之
          cellDom: cell, // 傳遞這個dom元素
          row: row, // 傳遞雙擊的行的數(shù)據(jù)
          property: column.property, // 傳遞雙擊的是哪個字段
        },
      }).$mount(cell.children[0]); // 5. $mount方法,用于將某個dom掛載到某個dom上
    },
    /**
     * 失去焦點的時候有以下操作
     *    1. 校驗新值是否等于原有值,若等于,說明用戶未修改,就不發(fā)請求。若不等于就發(fā)請求,然后更新tableData數(shù)據(jù)
     *    2. 然后使用$mount方法,掛載一個新的span標簽dom在頁面上,即恢復原樣,而span標簽也是實例化的哦
     * */
    saveRowData(params) {
      console.log("繼承的子組件傳遞過來的數(shù)據(jù)", params);
      // 1. 看看用戶是否修改了
      if (params.cellValue == this.oldCellValue) {
        console.log("未修改數(shù)據(jù),不用發(fā)請求");
      } else {
        params.row[params.property] = params.cellValue;
        // 這里模擬一下發(fā)了請求,得到最新表體數(shù)據(jù)以后,更新tableData
        setTimeout(() => {
          //        給那個數(shù)組的     第幾項            修改為什么值
          this.$set(this.tableData, params.row.index, params.row);
        }, 300);
      }
      // 2. 恢復dom節(jié)點成為原來的樣子,有下面兩種方式

      /**
       * 方式一:使用官方推薦的$mount去掛載到某個節(jié)點上,上方也是
       * */
      new extendComponents.spanC({
        propsData: {
          cellValue: params.cellValue,
        },
      }).$mount(params.cellDom.children[0]);

      /**
       * 方式二:使用原生js去清空原節(jié)點內(nèi)容,同時再添加子元素
       * */
      // let span = document.createElement("span"); // 創(chuàng)建一個span標簽
      // span.innerHTML = params.cellValue; // 指定span標簽的內(nèi)容的值
      // span.classList.add("cell"); // 給span標簽添加class為cell
      // params.cellDom.innerHTML = ""; // 清空剛操作的input標簽的內(nèi)容
      // params.cellDom.appendChild(span); // 再把span標簽給追加上去,恢復原樣
    },
  },
};
</script>

<style lang="less" scoped>
#app {
  width: 100%;
  height: 100vh;
  box-sizing: border-box;
  padding: 50px;
}
</style>

總結

使用Vue.extend()方法,可以繼承一些組件,甚至繼承一些復雜的組件,在實際業(yè)務場景中會有巧妙的使用。具體業(yè)務場景具體分析。

此外,上述代碼中是el-input的繼承,其實,我們也可以做el-select的繼承,思路和上方類似,這樣就可以在表格中雙擊單元格,選擇并更改對應的下拉框更改el-table的單元值了,比如如果有性別這一列,那是下拉框的形式的。道友們可以按照這個思路發(fā)散哦...

到此這篇關于如何巧用Vue.extend繼承組件實現(xiàn)el-table雙擊可編輯(不使用v-if、v-else)的文章就介紹到這了,更多相關Vue.extend實現(xiàn)el-table雙擊可編輯內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Vue中使用elementui與Sortable.js實現(xiàn)列表拖動排序

    Vue中使用elementui與Sortable.js實現(xiàn)列表拖動排序

    這篇文章主要為大家詳細介紹了Vue中使用elementui與Sortable.js實現(xiàn)列表拖動排序,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-04-04
  • vue中ref的用法小結

    vue中ref的用法小結

    在項目中使用ref時有時候直接取值,有時候返回的卻是一個數(shù)組,不知其中緣由,后查了一下ref用法,在這里給大家分享vue中ref的用法,感興趣的朋友一起看看吧
    2023-11-11
  • TypeScript基本類型 typeof 和keyof案例詳解

    TypeScript基本類型 typeof 和keyof案例詳解

    這篇文章主要介紹了TypeScript基本類型 typeof 和keyof案例詳解,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-10-10
  • vue+elementUI實現(xiàn)動態(tài)面包屑

    vue+elementUI實現(xiàn)動態(tài)面包屑

    這篇文章主要為大家詳細介紹了vue+elementUI實現(xiàn)動態(tài)面包屑,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-04-04
  • vue-music關于Player播放器組件詳解

    vue-music關于Player播放器組件詳解

    這篇文章主要為大家詳細介紹了vue-music關于Player播放器組件的相關資料,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • Vue中Layout內(nèi)部布局el-row、el-col的實現(xiàn)

    Vue中Layout內(nèi)部布局el-row、el-col的實現(xiàn)

    layout是一種非常方便的布局方式,本文主要介紹了Vue中Layout內(nèi)部布局el-row、el-col的實現(xiàn),具有一定的參考價值,感興趣的可以了解一下
    2024-07-07
  • Vue組件通信傳遞數(shù)據(jù)的三種方式

    Vue組件通信傳遞數(shù)據(jù)的三種方式

    這篇文章主要介紹了Vue組件通信傳遞數(shù)據(jù)的三種方式,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習吧
    2023-04-04
  • vue3 使用socket的完整代碼

    vue3 使用socket的完整代碼

    這篇文章主要介紹了vue3 使用socket的完整代碼,包括vue3客戶端和服務端的實例講解,本文給大家介紹的非常詳細,感興趣的朋友跟隨小編一起看看吧
    2024-03-03
  • vue-cli2.0轉3.0之項目搭建的詳細步驟

    vue-cli2.0轉3.0之項目搭建的詳細步驟

    這篇文章主要介紹了vue-cli2.0轉3.0之項目搭建的詳細步驟,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-12-12
  • Vue.js中用webpack合并打包多個組件并實現(xiàn)按需加載

    Vue.js中用webpack合并打包多個組件并實現(xiàn)按需加載

    對于現(xiàn)在前端插件的頻繁更新,我也是無力吐槽,但是既然入了前端的坑就得認嘛,所以多多少少要對組件化有點了解,下面這篇文章主要給大家介紹了在Vue.js中用webpack合并打包多個組件并實現(xiàn)按需加載的相關資料,需要的朋友可以參考下。
    2017-02-02

最新評論