vue 通用表格组件封装 附代码

以下是关于封装my-table表格组件的基本要求,理解即可
1.数据不能写死,动态传递表格渲染的数据;
2.结构不能写死:
(1)表头支持自定义;
(2)主体支持自定义;

基本步骤如下:

1.新建MyTable.vue文件

在这里插入图片描述

2.导入和注册

在这里插入图片描述

3.使用组件

在这里插入图片描述

4.数据准备(渲染表格所需要的数据来源)

在这里插入图片描述

5.父组件中的goods数据向子组件(MyTable.vue)传递数据

在这里插入图片描述

6.自定义表头

在这里插入图片描述

7.自定义表主体

在这里插入图片描述

代码结构如下所示,总共四个代码文件,如果只是为了学习表格组件封装,只需要看MyTable.vue以及app.vue即可

在这里插入图片描述

8.代码分享

app.vue代码如下:

<template>
  <div class="app">
    <div class="table-case">
      <MyTable :data="goods">
        <template #head>
          <th>编号</th>
          <th>图片</th>
          <th>名称</th>
          <th width="100px">标签</th>
        </template>
        <template #body="{ item, index }">
          <td>{{ index + 1 }}</td>
          <td>
            <img :src="item.picture" alt="" />
          </td>
          <td>{{ item.name }}</td>
          <td>
            <!-- 标签组件 -->
            <MyTag v-model="item.tag"></MyTag>
          </td>
        </template>
      </MyTable>
    </div>
  </div>
  <!-- 
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png" />
    <HelloWorld msg="Welcome to Your Vue.js App" />
  </div> -->
</template>

<script>
// import HelloWorld from "./components/HelloWorld.vue";
// my-tag组件的封装
// 1.创建组件-初始化
// 2.实现功能
// (1)双击显示,并且自动获取焦点;
// (2)失去焦点,隐藏输入框;
// (3)双击要回显标签信息;(回显的标签信息一定是父组件传过来的)
// (4)内容修改了,回车可以实现修改标签信息。
// --------------------------------------------------------------
// 封装my-table表格组件
// 1.数据不能写死,动态传递表格渲染的数据;
// 2.结构不能写死
// (1)表头支持自定义;
// (2)主体支持自定义;

import MyTag from "./components/MyTag.vue";
import MyTable from "./components/MyTable.vue";
export default {
  name: "TableCase",
  data() {
    return {
      tempText: "紫砂壶",
      tempText1: "茶壶",
      goods: [
        {
          id: 101,
          picture:
            "https://img.icons8.com/?size=100&id=37879&format=png&color=000000",
          name: "毛茸茸紫砂壶",
          tag: "紫砂锅",
        },
        {
          id: 102,
          picture:
            "https://img.icons8.com/?size=100&id=15585&format=png&color=000000",
          name: "巧克力紫砂壶",
          tag: "紫砂壶",
        },
        {
          id: 103,
          picture:
            "https://img.icons8.com/?size=100&id=81384&format=png&color=000000",
          name: "喵咪咪紫砂壶",
          tag: "暖手壶",
        },
      ],
    };
  },
  components: {
    MyTag,
    MyTable,
  },
};
</script>

<style scoped>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

MyTable.vue代码如下:

<template>
  <table class="my-table">
    <thead>
      <slot name="head"></slot>
    </thead>
    <tbody>
      <tr v-for="(item, index) in data" :key="item.id">
        <slot name="body" :item="item" :index="index"></slot>
      </tr>
    </tbody>
  </table>
</template>

<script>
export default {
  props: {
    data: {
      type: Array,
      required: true,
    },
  },
};
</script>

<style>
body {
  font-family: Arial, sans-serif;
  margin: 0;
  padding: 20px;
  background-color: #f4f4f4;
}

.app {
  max-width: 800px;
  margin: auto;
  background: white;
  border-radius: 8px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
  padding: 20px;
}

.table-case {
  overflow-x: auto; /* 对于大表格,添加水平滚动条 */
}

.my-table {
  width: 100%;
  border-collapse: collapse;
  margin: 20px 0;
}

.my-table th,
.my-table td {
  border: 1px solid #dddddd;
  text-align: center;
  padding: 12px;
}

.my-table th {
  background-color: #1c5d99; /* 表头背景颜色 */
  color: white; /* 表头字体颜色 */
}

.my-table tr:nth-child(even) {
  background-color: #f9f9f9; /* 斑马条纹效果 */
}

.my-table tr:hover {
  background-color: #f1f1f1; /* 鼠标悬停效果 */
}

.my-tag {
  display: inline-block;
  padding: 5px 10px;
  /* background-color: #f7f9fd; 标签背景颜色 */
  color: rgb(27, 25, 25); /* 标签字体颜色 */
  border-radius: 3px;
  font-size: 14px;
  /* border: 1px solid rgb(171, 164, 164); */
}

img {
  max-width: 80px; /* 确保图片不会过大 */
  height: auto;
}
</style>

MyTag.vue代码如下:

<template>
  <div class="my-tag">
    <input
      ref="inp"
      v-focus
      v-if="isEdit"
      type="text"
      class="input"
      placeholder="输入标签"
      @blur="isEdit = false"
      :value="value"
      @keyup.enter="handleEnter"
    />
    <div v-else class="text" @dblclick="handleClick">{{ value }}</div>
  </div>
</template>

<script>
export default {
  props: {
    value: String,
  },
  data() {
    return {
      isEdit: false,
    };
  },
  methods: {
    handleClick() {
      this.isEdit = true;
      //   //   vue是异步dom更新
      //   this.$nextTick(() => {
      //     //立刻获取焦点
      //     this.$refs.inp.focus();
      //   });
    },
    handleEnter(e) {
      // 子传父,将回车时,输入框的内容提交给父组件更新
      // 由于父组件用了v-model,触发事件需要触发input
      if (e.target.value.trim() === "") {
        return alert("标签内容不能为空");
      }
      console.log(e.target.value);

      this.$emit("input", e.target.value);
      this.isEdit = false;
    },
  },
};
</script>

<style lang="less" scoped>
.my-tag {
  cursor: pointer;
  //   background-color: aqua;
  .input {
    appearance: none;
    outline: none;
    border: 1px solid #ccc;
    width: 80px;
    height: 40px;
    box-sizing: border-box;
    padding: 10px;
    color: #666;
    &::placeholder {
      color: #666;
    }
  }
}
</style>

main.js代码如下:

import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false
//封装全局指令focus 否则MyTag中的获取焦点函数内要写很多次
Vue.directive('focus',{
    inserted(el){
      el.focus()
    }
})
new Vue({
  render: h => h(App),
}).$mount('#app')

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

细水长流者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值