亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

一次用vue3簡單封裝table組件的實(shí)戰(zhàn)過程

 更新時(shí)間:2022年12月22日 09:00:37   作者:摸魚大隊(duì)隊(duì)長  
之所以封裝全局組件是為了省事,所有的目的,全都是為了偷懶,下面這篇文章主要給大家介紹了關(guān)于用vue3簡單封裝table組件的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下

前言:

對(duì)于一個(gè)業(yè)務(wù)前端來講,工作中用的最多的組件我覺得大概率是table組件了,只要是數(shù)據(jù)展示就不可避免地用到這個(gè)組件。用久了就有點(diǎn)熟悉,就來鍛煉自己的封裝能力,為了更好的搬磚,封裝table組件。

首先,我們要思考我們封裝一個(gè)怎樣的表格,怎樣的形式更加方便。先定一個(gè)大概目標(biāo),往前走,剩下慢慢去完善。一般來說,我們更傾向于通過配置來實(shí)現(xiàn)表格,那就是說利用json格式來配置。

實(shí)現(xiàn)基礎(chǔ)功能表格

el-table中用el-table-columnprop屬性來對(duì)應(yīng)對(duì)象中的鍵名即可填入數(shù)據(jù),用 label 屬性來定義表格的列名。那么這兩個(gè)主要屬性可以通過動(dòng)態(tài)綁定來進(jìn)行賦值,然后使用v-for來進(jìn)行循環(huán)。

//app.vue
<script setup>
import TableVue from './components/Table.vue';
import {ref,reactive} from 'vue'
const tableData = [
  {
    date: '2016-05-03',
    name: 'Tom',
    address: 'No. 189, Grove St, Los Angeles',
  },
]
const options = reactive({
  column:[
    {
      prop:'date',
      label:'日期',
      width:180
    },
    {
      prop:'name',
      label:'名字',
      width:120
    },
    {
      prop:'address',
      label:'地址',
    }
  ]
})
</script>
<template>
<TableVue :table-data="tableData" :options="options"></TableVue>
</template>
<style scoped></style>
//table.vue
<script setup>
import { ref,defineProps } from 'vue'
const props= defineProps({
    options:Object,
    tableData:Array
})
const {column} = props.options
</script>
<template>
<el-table :data="tableData" style="width: 100vw;">
    <el-table-column v-for="(item,index) in column" :prop="item.prop" :label="item.label" :width="item.width??''" />
  </el-table>
</template>
<style scoped></style>

好了,我們完成了通過json格式的最簡單配置展示了數(shù)據(jù),僅僅只有這樣是遠(yuǎn)遠(yuǎn)不夠的,連最基本的增刪改查都沒有。那么我們接下來就來實(shí)現(xiàn)增刪改功能。對(duì)于增刪改的方法基本上就是父子組件之間的方法調(diào)用,值的傳遞使用,以及多了一個(gè)對(duì)話框來進(jìn)行值的交互。這里也不難,下面是關(guān)鍵代碼

//app.vue
//options里面新增以下屬性
  index:true,//是否有序號(hào) boolean  
  indexWidth:50,//序號(hào)列表寬度 number
  indexFixed:true,//序號(hào)是否為固定列 boolean
  menu:true, //是否有操作欄 boolean
  menuWidth:140,//操作欄寬度 number
  menuTitle:'操作2',//操作欄標(biāo)題 string
  menuFixed:true,//操作欄是否為固定列 boolean
  menuType:'text',//操作欄按鈕樣式 button/text
  
  //新增以下方法
  //刪除
const rowDel = (index,row)=>{
  console.log('del',index,row)
}
//編輯
const rowEdit=(type,row)=>{
  console.log(type,row)
}

<TableVue :table-data="tableData" :options="options" @row-del="rowDel" @row-edit="rowEdit"></TableVue>
//table.vue新增以下方法
<script setup>
const emits = defineEmits(["rowDel", "rowEdit"])
//把屬性解構(gòu)出來減少代碼量
const { options: op } = props
const { column } = props.options
//獲取子組件實(shí)例
const edit = ref('edit')
//行數(shù)據(jù)刪除時(shí)觸發(fā)該事件
const rowDel = (index, row) => {
    emits("rowDel", index, row)
}
//更新數(shù)據(jù)后確定觸發(fā)該事件
const editBefore = (row,type) => {
    //將行內(nèi)屬性轉(zhuǎn)為普通對(duì)象傳遞
    edit.value.openDialog(type,row,toRaw(column))
}
const rowEdit=(type,form)=>{
    emits("rowEdit",type,form)
}
</script>

<template>
    <div class="menuOp">
        <el-button type="danger" :icon="Plus" :size="op.size??'small'" @click="editBefore(_,'add')">新增</el-button>
    </div>
    <el-table :data="tableData" style="width: 100vw;" :size="op.size??'small'">
        <el-table-column v-if="op.index" type="index" :width="op.indexWidth ?? 50" />
        <el-table-column v-for="(item, index) in column" :prop="item.prop" :label="item.label" :width="item.width ?? ''" />
        <el-table-column :fixed="op.menuFixed ? 'right' : ''" :label="op.menuTitle" :width="op.menuWidth" v-if="op.menu">
            <template #default="scope">
                <el-button :type="op.menuType ?? 'primary'" size="small"
                    @click="editBefore(scope.row,'edit')">編輯</el-button>
                <el-button :type="op.menuType ?? 'primary'" size="small"
                    @click="rowDel(scope.$index, scope.row,'del')">刪除</el-button>
            </template>
        </el-table-column>
    </el-table>
    <!-- 對(duì)話框 -->
    <editDialog ref="edit" @edit-submit="rowEdit"></editDialog>
</template>

<style scoped>
.menuOp{
text-align: left;
}
</style>

進(jìn)一步定制化

雖然看著我們可以進(jìn)行簡單的增刪改,但是如果編輯有下拉框或者其他類型呢。表格行內(nèi)數(shù)據(jù)需要多樣性展示,而不是單純的純文本又該怎么辦呢。這時(shí)候我們需要用到vue里面的slot(插槽)來解決這個(gè)問題了。

插槽(slot)是 vue 為組件的封裝者提供的能力。允許開發(fā)者在封裝組件時(shí),把不確定的、希望由用戶指定的部分定義為插槽。

關(guān)鍵代碼截圖:

對(duì)話框我們利用插槽,那么同理,表格行內(nèi)的數(shù)據(jù)展示我們也可以進(jìn)行修改,來支持插槽

修改的關(guān)鍵代碼為:

增刪改基本功能到這里其實(shí)差不多,剩下就是一些細(xì)節(jié)性的判斷,接下來我們就來完成查詢部分的封裝。方法也是一樣,一般都是input框,其他有需求我們就利用插槽來實(shí)現(xiàn)。

//Search.vue
<script setup>
import { defineProps, onMounted, ref, defineEmits, toRaw, useSlots } from "vue";

const emits = defineEmits(["handleQuery", "handleReset"]);

const search = ref({});

const slots = useSlots();

const handleQuery = () => {
  emits("handleQuery", search.value);
};
const handleReset = () => {
  search.value = {};
  emits("handleReset");
};

const props = defineProps({
  row: {
    type: Object,
    default: () => {},
  },
  options: {
    type: Object,
    default: () => {},
  },
  search:{
    type:Object,
    default:()=>{}
  }
});

const column = toRaw(props.options.column);

onMounted(() => {
});
</script>

<template>
  <div style="text-align: left; margin-bottom: 20px">
    <el-form :inline="true" :model="search" class="demo-form-inline">
      <template v-for="(item, index) in props.row">
        <el-form-item
          :label="item.label"
          :label-width="`${item.searchLabel ?? options.searchLabel ?? 120}px`"
        >
          <slot
            v-if="slots.hasOwnProperty(`${item?.prop}Search`)"
            :name="`${item.prop}Search`"
          >
            <el-input
              v-model="search[item.prop]"
              :style="{ width: item.searchWidth ?? options.searchWidth + 'px' }"
              :placeholder="`請(qǐng)輸入${item.label}`"
            />
          </slot>
          <el-input
            v-else
            v-model="search[item.prop]"
            :style="{ width: item.searchWidth ?? options.searchWidth + 'px' }"
            :placeholder="`請(qǐng)輸入${item.label}`"
          />
        </el-form-item>
      </template>
    </el-form>
    <div>
      <el-button type="primary" size="small" @click="handleQuery"
        >查詢</el-button
      >
      <el-button type="primary" size="small" plain @click="handleReset"
        >重置</el-button
      >
    </div>
  </div>
</template>
//Table.vue
    <SearchVue
      :options="op"
      :row="slotCloumn"
      @handleReset="handleReset"
      @handleQuery="handleQuery"
      :search="search"
    >
      <template v-for="(item, index) in slotCloumn" #[item?.prop+`Search`]>
        <slot :name="`${item?.prop}Search`"></slot>
      </template>
    </SearchVue>

就暫時(shí)先寫到這里了,最開始是想通過封裝一個(gè)簡單的組件,來鞏固自己的vue3語法熟悉程度。后來發(fā)現(xiàn)因?yàn)樗接邢藜由鲜亲约邯?dú)立思考,有很多地方其實(shí)卡住了。比如值的傳遞是用provide(inject)比較好還是直接props來方便。值的改動(dòng)需不需要用到computed或者watch。插槽的寫法能否更加簡便,不需要一級(jí)一級(jí)傳遞的那種,越想越多問題。自己技術(shù)能力不夠這是最大的問題,想法過于宏大,能力卻不行,打算日后精進(jìn)自己的技術(shù),然后約上幾個(gè)伙伴繼續(xù)去完善,只有思維碰撞才能產(chǎn)出好的代碼。

最后,把全部代碼附上

//App.vue
<script setup>
import TableVue from "./components/Table.vue";
import { ref, reactive,toRaw } from "vue";

const tableData = [
  {
    date: "2016-05-03",
    name: "Tom",
    address: "No. 189, Grove St, Los Angeles",
  },
];

const options = reactive({
  index: true, //是否有序號(hào) boolean
  indexWidth: 50, //序號(hào)列表寬度 number
  indexFixed: true, //序號(hào)是否為固定列 boolean
  menu: true, //是否有操作欄 boolean
  menuWidth: 180, //操作欄寬度 number
  menuTitle: "操作2", //操作欄標(biāo)題 string
  menuFixed: true, //操作欄是否為固定列 boolean
  menuType: "text", //操作欄按鈕樣式 button/text
  searchLabel:150,//查詢框label的寬度
  searchWidth:200,//查詢框組件的寬度
  column: [
    {
      prop: "date",
      label: "日期",
      width: 180,
      searchWidth:220,
      searchLabel:100,//行內(nèi)的設(shè)置優(yōu)先級(jí)高于全局
    },
    {
      prop: "name",
      label: "名字",
      width: 120,
      searchWidth:180
    },
    {
      prop: "address",
      label: "地址",
      //是否在表單彈窗中顯示
      editDisplay: false,
      searchWidth:200
    },
  ],
});

const form = ref({})
const search = ref({})

//刪除
const rowDel = (index, row) => {
  console.log("del", index, row);
};
//編輯
const rowEdit = (type, row) => {
  // console.log(type, row);
  //這里因?yàn)闆]有思考明白到底如何利用v-model屬性進(jìn)行所有組件綁定傳遞,就使用這種蹩腳方法
  console.log(Object.assign(row.value,form.value))
};
const tip=(row)=>{
  console.log(row)
}
const handleReset=()=>{
  console.log('reset')
}
const handleQuery=(param)=>{
  let params = Object.assign(search.value,param)
  console.log(params)
}

</script>

<template>
  <TableVue
    :table-data="tableData"
    :options="options"
    @row-del="rowDel"
    @row-edit="rowEdit"
    v-model="form"
    @handleQuery="handleQuery"
    @handleReset="handleReset"
    :search="search"
  >
  <!-- 查詢框插槽 -->
  <template #dateSearch>
    <el-date-picker
        v-model="search.date"
        type="datetime"
        placeholder="Select date and time"
      />
  </template>
  <!-- 表格內(nèi)的插槽,插槽名為字段名 -->
  <template #date="{scope}">
    <el-tag>{{scope.row.date}}</el-tag>
  </template>
  <!-- 操作欄插槽 -->
  <template #menu="{scope}" >
    <el-button icon="el-icon-check"  @click="tip(scope.row)">自定義菜單按鈕</el-button>
  </template>
  <!-- 對(duì)話框插槽,插槽名字為對(duì)應(yīng)的字段名加上Form -->
    <template #dateForm>
      <el-date-picker
        v-model="form.date"
        type="datetime"
        placeholder="Select date and time"
      />
    </template>
  </TableVue>
</template>

<style scoped></style>
//Search.vue
<script setup>
import { defineProps, onMounted, ref, defineEmits, toRaw, useSlots } from "vue";
const emits = defineEmits(["handleQuery", "handleReset"]);
const search = ref({});
const slots = useSlots();
const handleQuery = () => {
  emits("handleQuery", search.value);
};
const handleReset = () => {
  search.value = {};
  emits("handleReset");
};
const props = defineProps({
  row: {
    type: Object,
    default: () => {},
  },
  options: {
    type: Object,
    default: () => {},
  },
  search:{
    type:Object,
    default:()=>{}
  }
});
const column = toRaw(props.options.column);
onMounted(() => {
});
</script>
<template>
  <div style="text-align: left; margin-bottom: 20px">
    <el-form :inline="true" :model="search" class="demo-form-inline">
      <template v-for="(item, index) in props.row">
        <el-form-item
          :label="item.label"
          :label-width="`${item.searchLabel ?? options.searchLabel ?? 120}px`"
        >
          <slot
            v-if="slots.hasOwnProperty(`${item?.prop}Search`)"
            :name="`${item.prop}Search`"
          >
            <el-input
              v-model="search[item.prop]"
              :style="{ width: item.searchWidth ?? options.searchWidth + 'px' }"
              :placeholder="`請(qǐng)輸入${item.label}`"
            />
          </slot>
          <el-input
            v-else
            v-model="search[item.prop]"
            :style="{ width: item.searchWidth ?? options.searchWidth + 'px' }"
            :placeholder="`請(qǐng)輸入${item.label}`"
          />
        </el-form-item>
      </template>
    </el-form>
    <div>
      <el-button type="primary" size="small" @click="handleQuery"
        >查詢</el-button
      >
      <el-button type="primary" size="small" plain @click="handleReset"
        >重置</el-button
      >
    </div>
  </div>
</template>
//table.vue
<script setup>
import { ref, defineProps, defineEmits, toRaw, onMounted, useSlots } from "vue";
import { Delete, Plus } from "@element-plus/icons-vue";
import editDialog from "./Dialog.vue";
import SearchVue from "./Search.vue";
const props = defineProps({
  options: Object,
  tableData: Array,
  modelValue: {
    type: Object,
    default: () => {},
  },
});
const emits = defineEmits([
  "rowDel",
  "rowEdit",
  "update:modelValue",
  "handleQuery",
]);
//把屬性解構(gòu)出來減少代碼量
const { options: op } = props;
const { column } = props.options;
//獲取編輯對(duì)話框里面所有屬性,用于動(dòng)態(tài)生成插槽
const slotCloumn = toRaw(column);
//獲取子組件實(shí)例
const edit = ref("edit");
//獲取插槽實(shí)例
const slots = useSlots();
//行數(shù)據(jù)刪除時(shí)觸發(fā)該事件
const rowDel = (index, row) => {
  emits("rowDel", index, row);
};
//更新數(shù)據(jù)后確定觸發(fā)該事件
const editBefore = (row, type) => {
  //將行內(nèi)屬性轉(zhuǎn)為普通對(duì)象傳遞
  edit.value.openDialog(type, row, toRaw(column));
};
const rowEdit = (type, form) => {
  emits("rowEdit", type, form);
  emits("update:modelValue", form);
};
const handleQuery = (search) => {
  emits("handleQuery", search);
};
const handleReset = () => {
  emits("handleReset");
};
onMounted(() => {
  console.log("slots", slots);
});
</script>
<template>
  <div>
    <SearchVue
      :options="op"
      :row="slotCloumn"
      @handleReset="handleReset"
      @handleQuery="handleQuery"
      :search="search"
    >
      <template v-for="(item, index) in slotCloumn" #[item?.prop+`Search`]>
        <slot :name="`${item?.prop}Search`"></slot>
      </template>
    </SearchVue>
  </div>
  <div class="menuOp">
    <el-button
      type="danger"
      :icon="Plus"
      :size="op.size ?? 'small'"
      @click="editBefore(_, 'add')"
      >新增</el-button
    >
  </div>
  <el-table :data="tableData" style="width: 100vw" :size="op.size ?? 'small'">
    <el-table-column
      v-if="op.index"
      type="index"
      :width="op.indexWidth ?? 50"
    />
    <template v-for="(item, index) in column">
      <el-table-column
        :label="item.label"
        v-if="slots.hasOwnProperty(item?.prop)"
      >
        <template #default="scope">
          <slot :name="item.prop" :scope="scope"></slot>
        </template>
      </el-table-column>
      <el-table-column
        v-else
        :prop="item.prop"
        :label="item.label"
        :width="item.width ?? ''"
      />
    </template>
    <el-table-column
      :fixed="op.menuFixed ? 'right' : ''"
      :label="op.menuTitle"
      :width="op.menuWidth"
      v-if="op.menu"
    >
      <template #default="scope">
        <el-button
          :type="op.menuType ?? 'primary'"
          size="small"
          @click="editBefore(scope.row, 'edit')"
          >編輯</el-button
        >
        <el-button
          :type="op.menuType ?? 'primary'"
          size="small"
          @click="rowDel(scope.$index, scope.row, 'del')"
          >刪除</el-button
        >
        <!-- 利用作用域插槽將數(shù)據(jù)傳遞過去 -->
        <slot name="menu" :scope="scope"></slot>
      </template>
    </el-table-column>
  </el-table>
  <!-- 對(duì)話框 -->
  <editDialog ref="edit" @edit-submit="rowEdit">
    <template v-for="(item, index) in slotCloumn" #[item?.prop+`Form`]="scope">
      <slot :name="`${item?.prop}Form`" v-bind="scope"></slot>
    </template>
  </editDialog>
</template>

<style scoped>
.menuOp {
  text-align: left;
}
</style>
//Dialog.vue
<script setup>
import { ref, defineExpose, defineEmits, useSlots, onMounted } from "vue";
const emits = defineEmits(["editSubmit"]);
const dialogFormVisible = ref(false);
const form = ref({});
const tp = ref("");
let columns = [];
//獲取當(dāng)前已實(shí)例化的插槽,然后去判斷插槽是否使用了
const slots = useSlots();

const openDialog = (type, row, column) => {
  dialogFormVisible.value = true;
  columns = column;
  tp.value = type;
  if (type === "edit") {
    //如果編輯框設(shè)置了editDisplay為false,則刪除該屬性
    columns.map((x) => {
      if (x.editDisplay === false) {
        delete row[x.prop];
      }
    });
    form.value = JSON.parse(JSON.stringify(row));
  }else{
    form.value={}
  }
};
const handleSubmit = () => {
  emits("editSubmit", tp, form);
};
onMounted(() => {
  console.log("===", slots);
});
defineExpose({
  openDialog,
});
</script>
<template>
  <el-dialog v-model="dialogFormVisible" append-to-body :title="tp==='add'?'新增':'編輯'">
    <el-form :model="form">
      <template v-for="(item, index) in columns">
        <el-form-item
          v-if="tp==='add'?item.addDisplay??true:item.editDisplay ?? true"
          :key="index"
          :label="item.label"
          label-width="120px"
        >
          <slot
            :name="`${item?.prop}Form`"
            v-if="slots.hasOwnProperty(`${item?.prop}Form`)"
          >
            <!-- 因?yàn)樵趖able組件已經(jīng)開始生成所有關(guān)于編輯的插槽,所以全部都有實(shí)例,需要給個(gè)默認(rèn)顯示,否則會(huì)空白 -->
            <el-input v-model="form[item?.prop]" />
          </slot>
          <el-input v-model="form[item?.prop]" v-else />
        </el-form-item>
      </template>
    </el-form>
    <template #footer>
      <span class="dialog-footer">
        <el-button @click="dialogFormVisible = false">取消</el-button>
        <el-button type="primary" @click="handleSubmit"> 確認(rèn) </el-button>
      </span>
    </template>
  </el-dialog>
</template>

總結(jié)

到此這篇關(guān)于用vue3簡單封裝table組件的文章就介紹到這了,更多相關(guān)vue3封裝table組件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Vue中父子組件通信與事件觸發(fā)的深入講解

    Vue中父子組件通信與事件觸發(fā)的深入講解

    組件是Vue核心功能之一,合理的組件化,可以減少我們代碼的冗余,提高項(xiàng)目的可維護(hù)性,下面這篇文章主要給大家介紹了關(guān)于Vue中父子組件通信與事件觸發(fā)的相關(guān)資料,需要的朋友可以參考下
    2022-03-03
  • Vue學(xué)習(xí)之組件用法實(shí)例詳解

    Vue學(xué)習(xí)之組件用法實(shí)例詳解

    這篇文章主要介紹了Vue學(xué)習(xí)之組件用法,結(jié)合實(shí)例形式分析了vue.js組件的使用流程、模板、父子組件、插槽slot等相關(guān)原理與操作技巧,需要的朋友可以參考下
    2020-01-01
  • Vue?element樹形控件添加虛線詳解

    Vue?element樹形控件添加虛線詳解

    這篇文章主要為大家介紹了Vue?element樹形控件添加虛線,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助<BR>
    2021-11-11
  • vue項(xiàng)目支付功能代碼詳解

    vue項(xiàng)目支付功能代碼詳解

    這篇文章主要介紹了vue項(xiàng)目支付功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-01-01
  • vue中路由跳轉(zhuǎn)的方式有哪些你知道嗎

    vue中路由跳轉(zhuǎn)的方式有哪些你知道嗎

    這篇文章主要為大家介紹了vue路由跳轉(zhuǎn)的方式,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2021-11-11
  • Vue官方推薦AJAX組件axios.js使用方法詳解與API

    Vue官方推薦AJAX組件axios.js使用方法詳解與API

    axios是Vue官方推薦AJAX組件,下面為大家介紹axios.js庫的詳細(xì)使用方法與API介紹
    2018-10-10
  • Vue.js快速入門實(shí)例教程

    Vue.js快速入門實(shí)例教程

    vue是法語中視圖的意思,Vue.js是一個(gè)輕巧、高性能、可組件化的MVVM庫,同時(shí)擁有非常容易上手的API。這篇文章主要介紹了Vue.js快速入門實(shí)例教程的相關(guān)資料,需要的朋友可以參考下
    2016-10-10
  • vue如何實(shí)現(xiàn)路由跳轉(zhuǎn)到外部鏈接界面

    vue如何實(shí)現(xiàn)路由跳轉(zhuǎn)到外部鏈接界面

    這篇文章主要介紹了vue如何實(shí)現(xiàn)路由跳轉(zhuǎn)到外部鏈接界面,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。
    2022-10-10
  • Vue.js分頁組件實(shí)現(xiàn):diVuePagination的使用詳解

    Vue.js分頁組件實(shí)現(xiàn):diVuePagination的使用詳解

    這篇文章主要介紹了Vue.js分頁組件實(shí)現(xiàn):diVuePagination的使用詳解,需要的朋友可以參考下
    2018-01-01
  • 一文了解axios和vue的整合操作

    一文了解axios和vue的整合操作

    axios作為Vue生態(tài)系統(tǒng)中濃墨重彩的一筆,我學(xué)習(xí)這個(gè)東西也是花了一定的時(shí)間的,下面這篇文章主要給大家介紹了關(guān)于axios和vue整合操作的相關(guān)資料,需要的朋友可以參考下
    2022-04-04

最新評(píng)論