前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >VUE实现一个列表清单【props 父子组件通信、slot插槽的使用、全局自定义指令的封装、$nextTick解决异步DOM更新、巧用v-model简化父子组件之间的通信、触发事件的事件源event】

VUE实现一个列表清单【props 父子组件通信、slot插槽的使用、全局自定义指令的封装、$nextTick解决异步DOM更新、巧用v-model简化父子组件之间的通信、触发事件的事件源event】

作者头像
HelloWorldZ
发布2024-03-20 19:02:11
790
发布2024-03-20 19:02:11
举报
文章被收录于专栏:前端开发前端开发

引子

现在决定就走前端的这条道路了,当然更希望 2026 年考公上岸。这周一直在巩固 VUE,在仓库里看见了这个去年暑假学习VUE的时候练习的一个Demo,发现挺不错的,打算写一篇博客。

这个Demo,或许看起来平平无奇,但它深深凹印着VUE的基础篇章:

  • props emit 绘制了一条神秘的密码,实现了父子组件间的暗号交流
  • 开启了slot插槽的大门,使得组件灵活性,复用性更高 ⭐⭐⭐⭐⭐
  • 全局自定义指令的封装
  • 使用$nextTick演示了如何优雅的应对异步DOM更新,感觉就像是有了掌控时间的超能力
  • 巧用v-model,简洁地优化了父子组件之间的通信 ⭐⭐⭐⭐⭐
  • 触发事件的事件源event
  • ref 、$refs 的绑定和使用
  • 原生HTML5 Drag and Drop API 的使用

预览

项目文件结构

代码语言:javascript
复制
-db 数据库的存放位置
 |- index.json 组织和管理数据库中的数据
-node_modules 包含了通过 npm 或 yarn 安装的所有依赖包
-public 这是公共资源目录,其中的文件和内容会被直接复制到构建输出的根目录
 |- favicon.ico 网页的图标,显示在浏览器的标签页上
 |- index.html 这是项目的入口HTML文件,用于加载Vue应用
-src 源代码目录,包含了项目的所有源代码文件
 |- assets 存放所有静态资源文件,如图片、样式文件等
    |- logo.png 项目的Logo图片
-components 存放所有的Vue组件
 |- MyTable.vue 一个自定义的Vue表格组件
 |- MyTag.vue 一个自定义的Vue标签组件
-directives 存放所有的全局Vue指令
 |- globalDirectives.js 全局Vue指令的定义和注册
-store Vuex存储管理,用于管理应用的状态
 |- index.js Vuex存储的入口文件,定义和配置了整个存储系统
-utils 工具函数和实用程序的集合
-App.vue 应用的根组件
-main.js 应用的入口文件,通常在这里初始化Vue应用并挂载到DOM中
-.browserslistrc 定义了Babel和Browserify的浏览器兼容性目标
-.editorconfig 定义了不同编辑器的代码风格和格式
-.eslintrc.js ESLint的配置文件,用于代码质量检查和静态代码分析
-.gitignore Git版本控制系统忽略的文件和目录列表
-babel.config.js Babel的配置文件,用于转译ES6+代码到ES5
-package.json 包含了项目的元信息和依赖包列表
-README.md 项目说明文档
-vue.config.js Vue CLI项目的配置文件,可以进行各种自定义配置
-yarn.lock Yarn依赖包的锁定文件,确保依赖包的版本一致性

数据准备

代码语言:javascript
复制
{
  "goods": [
    {
      "id": 1,
      "picture": "https://static.nike.com.cn/a/images/t_PDP_864_v1/f_auto,b_rgb:f5f5f5/a43f1f52-6850-4cab-837f-b93ff752f16d/ja-1-ep-%E5%B0%8F%E9%87%91%E9%BE%99%E9%BE%99%E5%B9%B4%E6%AC%BE%E5%AE%9E%E6%88%98%E8%B4%BE%E8%8E%AB%E5%85%B0%E7%89%B9%E7%94%B7%E5%AD%90%E7%AF%AE%E7%90%83%E9%9E%8B-ZLQQx9.png",
      "name": "“小金龙”龙年款实战贾莫兰特男子篮球鞋",
      "tag": "篮球鞋"
    },
    {
      "id": 2,
      "picture": "https://static.nike.com.cn/a/images/t_PDP_864_v1/f_auto,b_rgb:f5f5f5,u_126ab356-44d8-4a06-89b4-fcdcc8df0245,c_scale,fl_relative,w_1.0,h_1.0,fl_layer_apply/dcb6b305-9d83-43b8-8b93-d7761ab4d6a8/air-jordan-legacy-312-%E9%9D%92%E9%BE%99%E7%94%B7%E5%AD%90%E8%BF%90%E5%8A%A8%E9%9E%8B-bssr37.png",
      "name": "Air Jordan Legacy 312 “青龙”男子运动鞋",
      "tag": "运动鞋"
    },
    {
      "id": 3,
      "picture": "https://static.nike.com.cn/a/images/t_PDP_864_v1/f_auto,b_rgb:f5f5f5/406bd965-8f3e-4af8-bfe1-c0375cd4fd19/custom-sabrina-1-by-you.png",
      "name": "Sabrina 1 By You 专属定制篮球鞋",
      "tag": "定制"
    },
    {
      "id": 4,
      "picture": "https://static.nike.com.cn/a/images/t_PDP_864_v1/f_auto,b_rgb:f5f5f5/ba3a7f48-77d9-49aa-ad2b-24d0df830bac/lebron-21-ep-%E7%94%B7%E5%AD%90%E7%AF%AE%E7%90%83%E9%9E%8B-wK6QND.png",
      "name": "LeBron XXI EP 男子篮球鞋",
      "tag": "人物系列"
    }
  ]
}

MyTable.vue

  • 可自定义表头和表体,通过插槽的方式进行传入。
  • 支持拖拽排序功能,通过dragstart,drop事件实现元素的拖拽排序功能。
代码语言:javascript
复制
<template>
  <div class="table-case">
    <table class="my-table">
      <thead>
        <tr>
          <slot name="head"></slot>
        </tr>
      </thead>
      <tbody>
        <tr v-for="(item, index) in data" :key="index" @dragstart="dragStart(index)" @drop="drop(index)" @dragover.prevent>
          <slot name="body" :item="item" :index="index"></slot>
        </tr>
      </tbody>
    </table>
  </div>
</template>

<script>
export default {
  name: 'MyTable',
  props: {
    data: {
      type: Array,
      require: true
    }
  },
  data () {
    return {
      draggedIndex: 0,
      endIndex: 0
    }
  },
  methods: {
    dragStart (index) {
      this.draggedIndex = index
    },
    drop (index) {
      this.endIndex = index
      const obj = {
        start: this.draggedIndex,
        end: this.endIndex
      }
      this.$emit('swapThem', obj)
    }
  }
}
</script>

<style lang="less" scoped>
.table-case {
  width: 1000px;
  margin: 50px auto;
  img {
    width: 100px;
    height: 100px;
    object-fit: contain;
    vertical-align: middle;
  }

  .my-table {
    width: 100%;
    border-spacing: 0;
    tr {
      transition:  background-color .3s;
      &:hover {
        background-color: rgba(0,0,0,.4);
        color: #fff;
        cursor: pointer;
      }
    }
    img {
      width: 100px;
      height: 100px;
      object-fit: contain;
      vertical-align: middle;
    }
    th {
      background: #000;
      color:#fff;
      border-bottom: 2px solid #ccc;
    }
    td {
      border-bottom: 1px dashed #ccc;
    }
    td,
    th {
      text-align: center;
      padding: 10px;
      transition: all 0.5s;
      &.red {
        color: red;
      }
    }
    .none {
      height: 100px;
      line-height: 100px;
      color: #999;
    }
  }
}
</style>

MyTag.vue

  • 双击标签即可编辑,编辑时显示输入框,失焦或按下 Enter 键即可提交修改。
  • 使用了自定义指令v-focus来实现输入框聚焦功能。
代码语言:javascript
复制
<template>
  <div class="my-tag">
    <input
      v-if="isEdit"
      v-focus
      @blur="isEdit = false"
      ref="inp"
      class="input"
      type="text"
      placeholder="输入标签"
      :value="value"
      @keyup.enter="handleEnter"
    />
    <div
      v-else
      class="text"
      @dblclick="handleClick"
    >
      {{ value }}
    </div>
  </div>
</template>

<script>
export default {
  name: 'MyTag',
  props: {
    value: {
      type: String
    }
  },
  data () {
    return {
      isEdit: false
    }
  },
  methods: {
    handleClick () {
      // 切换显示状态 (Vue是异步Dom更新)
      this.isEdit = true
      // 立刻获取焦点
      // this.$nextTick(() => {
      //   console.log(this.$refs)
      //   this.$refs.inp.focus()
      // })
    },
    handleEnter (e) {
      this.$emit('input', e.target.value)
      this.isEdit = false
    }
  }
}
</script>

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

App.vue

代码语言:javascript
复制
<template>
  <div class="table-case">
    <MyTable :data="goodList" v-on:swapThem="swapThem">
      <template #head>
          <th>编号</th>
          <th>商品名</th>
          <th>商品展示</th>
          <th width="100px"></th>
      </template>
      <!-- 解构也是可以的 #body="{ item, index }" -->
      <template #body="slotProps">
        <td>{{ slotProps.index + 1 }}</td>
          <td>{{ slotProps.item.name }}</td>
          <td>
            <img :src="slotProps.item.picture" />
          </td>
          <td>
          <MyTag v-model="slotProps.item.tag"></MyTag>
      </td>
      </template>
    </MyTable>
  </div>
</template>

<script>
import MyTable from './components/MyTable.vue'
import MyTag from './components/MyTag.vue'
import axios from 'axios'
export default {
  name: 'TableCase',
  components: {
    MyTable,
    MyTag
  },
  data () {
    return {
      goodList: []
    }
  },
  created () {
    this.fetchListItem()
  },
  methods: {
    async fetchListItem () {
      axios.get('http://localhost:3000/goods').then((res) => {
        this.goodList = res.data
      })
    },
    swapThem (value) {
      const { start, end } = value
      // 交换元素位置
      const removedStart = this.goodList.splice(start, 1)[0]
      const removedEnd = this.goodList.splice(end - 1, 1, removedStart)[0]
      this.goodList.splice(start, 0, removedEnd)

      console.log(this.goodList)
    }
  }
}
</script>

<style lang="less" scoped>

</style>

自定义指令

globalDirectives.js

代码语言:javascript
复制
import Vue from 'vue'

// 全局指令 focus
Vue.directive('focus', {
  inserted (el, binding) {
    el.focus()
  }
})

小结

很简单的一个 Demo

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-01-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 引子
  • 预览
  • 项目文件结构
  • 数据准备
  • MyTable.vue
  • MyTag.vue
  • App.vue
  • 自定义指令
  • 小结
相关产品与服务
腾讯云代码分析
腾讯云代码分析(内部代号CodeDog)是集众多代码分析工具的云原生、分布式、高性能的代码综合分析跟踪管理平台,其主要功能是持续跟踪分析代码,观测项目代码质量,支撑团队传承代码文化。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档