• vue3.2 封装一个 可编辑的table插件


    vue3.2 封装一个 可编辑的table插件

    1:插件的 封装 步骤

    1-1:插件 components / editTable / EditTable.vue

    <!-- -->
    <template>
      <div>EditTable</div>
    </template>
    
    <script setup lang="ts" name='EditTable' >
    import { } from 'vue';
    </script >
    <style  lang="scss" scoped>
    </style>
    

    1-2:插件 components / index.ts

    import type { Component } from 'vue'
    import EditTable from './editTable/EditTable.vue'
    
    interface APP_COMPONENTS {
      [key: string]: Component // 字段扩展声明
    }
    
    const components = <APP_COMPONENTS>{
      EditTable
    }
    // 用于全局挂载
    export default {
      install(app: any) {
        for (let com in components) {
          app.component(com, components[com])
        }
      }
    }
    
    // 默认导出 用于局部使用
    export { EditTable }
    
    

    1-3:插件挂载 main.ts

    import { createApp } from 'vue'
    import App from './App.vue'
    
    import MyUI from '@/components/index.ts'
    
    const app = createApp(App)
    
    app.use(MyUI)
    app.mount('#app')
    
    

    1-4:插件的全局使用

    <template>
    	<edit-table></edit-table>
    </template>
    

    1-5:插件的按需使用

    <!--
    描述:
      作者:xzl
      时间:0623132206
    -->
    <template>
      <div>
        <edit-table></edit-table>
      </div>
    </template>
    
    <script setup lang="ts" name="Home">
    import { EditTable } from '@/components/index.ts'
    import {} from 'vue'
    </script>
    <style lang="scss" scoped></style>
    
    

    2:插件的 功能实现

    2-1:插件 components / editTable / EditTable.vue

    <!-- 可编辑table -->
    <template>
      <table border="1" class="edit-table">
        <thead>
          <tr>
            <th v-for="item of tHeader" :key="item.key">
              {{ item.text }}
            </th>
          </tr>
        </thead>
        <tbody>
          <tr v-for="(item, index) of tBody" :key="item.id">
            <td
              v-for="(value, key) in item"
              :key="key"
              @click.stop="showEditInput($event, key, index)"
            >
              {{ value }}
            </td>
          </tr>
        </tbody>
      </table>
    </template>
    
    <script setup lang="ts" name="EditTable">
    import EditInput from './EditInput.vue'
    import { ref, toRefs, reactive } from 'vue'
    const props = defineProps({
      data: {
        type: Object,
        default: () => ({
          tHeader: [],
          tBody: []
        })
      }
    })
    const emit = defineEmits(['submit'])
    const { tHeader, tBody } = toRefs(props.data)
    let editInputApp: any = null
    const state = reactive({
      key: '',
      value: '',
      index: '-1',
      text: ''
    })
    // 显示可编辑的input
    const showEditInput = (event: any, key: any, index: any) => {
      // 1:点击的时候,先移除可编辑的input
      editInputApp && removeEditInputApp()
      if (!checkEditTable(key)) return // 非 可编辑的选项 跳出
    
      const target = event.target
      const oFrag = document.createDocumentFragment()
      editInputApp = createApp(EditInput, {
        value: target.textContent,
        setValue
      })
      if (editInputApp) {
        editInputApp.mount(oFrag)
        target.appendChild(oFrag)
        target.querySelector('.edit-input').select()
      }
      setDate({ index, key, text: findText(key) })
    }
    // 设置编辑的文本数据
    function setDate({ index, key, text, value = '' }) {
      state.index = index
      state.key = key
      state.text = text
      state.value = value
    }
    // 寻找 可编辑的 text文本
    function findText(key: any) {
      const { text } = tHeader.value.find((item: any) => item.key === key)
      return text
    }
    // 设置 可编辑input 修改 table的数据 + 移除可编辑组件
    function setValue(value: any) {
      state.value = value
      emit('submit', { ...state }, removeEditInputApp)
    }
    // 移除 可编辑的input 并且清空 state状态数据
    function removeEditInputApp() {
      editInputApp && editInputApp.unmount()
      setDate({
        key: '',
        value: '',
        index: '-1',
        text: ''
      })
    }
    // 点击 找到 可以编辑的 td项
    function checkEditTable(key: any) {
      const { editable } = tHeader.value.find((item: any) => item.key === key)
      return editable
    }
    // 点击外层 移除掉 可编辑的事件
    window.addEventListener('click', removeEditInputApp, false)
    </script>
    <style lang="scss" scoped>
    .edit-table {
      width: 100%;
      border-collapse: collapse;
      tr {
        height: 44px;
      }
      td {
        position: relative;
        text-align: center;
        cursor: pointer;
      }
    }
    </style>
    

    2-2:插件 components / editTable / EditInput.vue

    <!-- 可编辑的input -->
    <template>
      <input
        type="text"
        class="edit-input"
        :value="value"
        @input="onInput"
        @blur="onBlur"
        @click="onClick"
      />
    </template>
    
    <script setup lang="ts" name="EditInput">
    import { ref } from 'vue'
    const props = defineProps({
      value: {
        type: String,
        default: ''
      },
      setValue: {
        type: Function,
        default: () => {}
      }
    })
    const inputVal = ref(props.value)
    const onInput = (event: any) => {
      inputVal.value = event.target.value.trim()
    }
    const onBlur = (event: any) => {
      props.setValue(inputVal.value)
    }
    const onClick = (event: any) => {
      event.stopPropagation()
    }
    </script>
    <style lang="scss" scoped>
    .edit-input {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      border: 1px solid yellow;
      text-align: center;
      outline: none;
    }
    </style>
    
    

    1-2:插件 components / index.ts

    import type { Component } from 'vue'
    import EditTable from './editTable/EditTable.vue'
    
    interface APP_COMPONENTS {
      [key: string]: Component // 字段扩展声明
    }
    
    const components = <APP_COMPONENTS>{
      EditTable
    }
    // 用于全局挂载
    export default {
      install(app: any) {
        for (let com in components) {
          app.component(com, components[com])
        }
      }
    }
    
    // 默认导出 用于局部使用
    export { EditTable }
    
    

    1-3:插件挂载 main.ts

    import { createApp } from 'vue'
    import App from './App.vue'
    
    import MyUI from '@/components/index.ts'
    
    const app = createApp(App)
    
    app.use(MyUI)
    app.mount('#app')
    
    

    2-4:插件的全局使用

    <!--
    描述:
      作者:xzl
      时间:0623132206
    -->
    <template>
      <div>
        Home
        <edit-table :data="tabelData" @submit="submit"></edit-table>
      </div>
    </template>
    
    <script setup lang="ts" name="Home">
    import { EditTable } from '@/components/index.ts'
    import { ref } from 'vue'
    const tabelData = ref({
      tHeader: [
        {
          key: 'id',
          text: '学号',
          editable: false
        },
        {
          key: 'name',
          text: '名称',
          editable: false
        },
        {
          key: 'age',
          text: '年龄',
          editable: false
        },
        {
          key: 'chinese',
          text: '语文',
          editable: true
        },
        {
          key: 'math',
          text: '数学',
          editable: true
        },
        {
          key: 'english',
          text: '英语',
          editable: true
        }
      ],
      tBody: [
        {
          id: '1',
          name: 'xpl',
          age: 16,
          chinese: 121,
          math: 188,
          english: 111
        },
        {
          id: '2',
          name: 'ppp',
          age: 18,
          chinese: 222,
          math: 223,
          english: 224
        },
        {
          id: '3',
          name: 'qqq',
          age: 23,
          chinese: 331,
          math: 332,
          english: 333
        }
      ]
    })
    const submit = ({ index, key, value, text }, removeInput) => {
      // console.log('submit', index, key, value, text)
      if (tabelData.value.tBody[index][key] != value) {
        const cfm = window.confirm(`
          你确定讲 ${index}${text} 字段的内容修改威 ${value} 吗?
        `)
        if (cfm) {
          tabelData.value.tBody = tabelData.value.tBody.map((item, idx) => {
            index === idx && (item[key] = value)
            return item
          })
        } else {
          removeInput()
        }
      }
    }
    </script>
    <style lang="scss" scoped></style>
    
    

    2-5 效果

      • 在这里插入图片描述
    • 点击

      • 在这里插入图片描述
    • 修改

      • 在这里插入图片描述
    • 结果

      • 在这里插入图片描述
  • 相关阅读:
    每日一题:编写程序,使程序分别输出两个整数的加减乘除运算结果
    STDF-Viewer 解析工具说明
    面试经典-9-跳跃游戏
    LeetCode790多米诺和托米诺平铺
    字符串匹配算法(BF、KMP)
    微信小游戏现在已不“小”了?
    内网穿透ngrok
    Kettle连接Oracle(Oracle19c&Oracle11g)
    Serverless之Knative部署应用实例;
    ent M2M模型在pxc集群中的一个大坑
  • 原文地址:https://blog.csdn.net/weixin_43845137/article/details/127113894