当前位置: 首页 > article >正文

vue 商品列表案例

my-tag 标签组件的封装

1. 创建组件 - 初始化

2. 实现功能

   (1) 双击显示,并且自动聚焦

       v-if v-else @dbclick 操作 isEdit

       自动聚焦:

       1. $nextTick => $refs 获取到dom,进行focus获取焦点

       2. 封装v-focus指令

   (2) 失去焦点,隐藏输入框

       @blur 操作 isEdit 即可

   (3) 回显标签信息

       回显的标签信息是父组件传递过来的

       v-model实现功能 (简化代码)  v-model => :value 和 @input

       组件内部通过props接收, :value设置给输入框

   (4) 内容修改了,回车 => 修改标签信息

       @keyup.enter, 触发事件 $emit('input', e.target.value)

---------------------------------------------------------------------

my-table 表格组件的封装

1. 数据不能写死,动态传递表格渲染的数据  props

2. 结构不能写死 - 多处结构自定义 【具名插槽】

   (1) 表头支持自定义

   (2) 主体支持自定义

源码:

components

        MyTag.vue

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

<script>
export default {
    data (){
        return{
            isShow : false
        }
    },
    props:{
        value : String      
    },
    methods:{
        handleClick(){
            this.isShow = true
            // this.$nextTick(() =>{
            //     this.$refs.ipt.focus()
            // })
        },
        handleEnter(e){
            if (e.target.value.trim() == '')
            return alert('更改为空,请重新更改')
            this.$emit("input",e.target.value)
            this.isShow = false
        }
    }
}
</script>

<style lang="less" scoped>
    .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>

MyTable.vue

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

<script>
export default {
    props:{
        goods : Array
    }
}
</script>

<style lang="less" scoped>
.my-table {
  width: 100%;
  border-spacing: 0;
  img {
    width: 100px;
    height: 100px;
    object-fit: contain;
    vertical-align: middle;
  }
  th {
    background: #f5f5f5;
    border-bottom: 2px solid #069;
  }
  td {
    border-bottom: 1px dashed #ccc;
  }
  td,
  th {
    text-align: center;
    padding: 10px;
    transition: all .5s;
    &.red {
      color: red;
    }
  }
  .none {
    height: 100px;
    line-height: 100px;
    color: #999;
  }
}

</style>

 

 App.vue

<template>
  <div class="table-case">
    <MyTable :goods="goods">
      <template #head>
        <tr>
          <th>编号</th>
          <th>图片</th>
          <th>名称</th>
          <th width="100px">标签</th>
        </tr>
      </template>
      <template #body="{item,index}">
        <td>{{index+1}}</td>
          <td><img :src="item.picture" /></td>
          <td>{{ item.name }}</td>
          <td>
            <MyTag v-model="item.tag"></MyTag>
          </td>
      </template>
    </MyTable>
  </div>
</template>

<script>
import MyTag from './components/MyTag.vue';
import MyTable from './components/MyTable.vue';
export default {
  name: 'TableCase',
  data () {
    return {
      goods: [
        { id: 101, picture: 'https://yanxuan-item.nosdn.127.net/f8c37ffa41ab1eb84bff499e1f6acfc7.jpg', name: '梨皮朱泥三绝清代小品壶经典款紫砂壶', tag: '茶具' },
        { id: 102, picture: 'https://yanxuan-item.nosdn.127.net/221317c85274a188174352474b859d7b.jpg', name: '全防水HABU旋钮牛皮户外徒步鞋山宁泰抗菌', tag: '男鞋' },
        { id: 103, picture: 'https://yanxuan-item.nosdn.127.net/cd4b840751ef4f7505c85004f0bebcb5.png', name: '毛茸茸小熊出没,儿童羊羔绒背心73-90cm', tag: '儿童服饰' },
        { id: 104, picture: 'https://yanxuan-item.nosdn.127.net/56eb25a38d7a630e76a608a9360eec6b.jpg', name: '基础百搭,儿童套头针织毛衣1-9岁', tag: '儿童服饰' },
      ]
    }
  },
  components:{
    MyTag,
    MyTable
  }
}
</script>

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

main.js

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

Vue.config.productionTip = false

Vue.directive("focus",{
  //指令所在的dom元素插入到页面中时触发
  inserted(el){
    el.focus()
  }
})

new Vue({
  render: h => h(App),
}).$mount('#app')

 运行结果:

双击标签后输入框自动获取焦点,并且把未更改以前的标签名显示到输入框上面。

 回车以后更改完成

 更改空白的话弹出提示

这些逻辑实现起来很简单,主要是表单中的表头和主体都可以进行自定义,这其中使用到了作用域插槽来传参。对组件化有着比较好的诠释。


http://www.kler.cn/a/161773.html

相关文章:

  • 鸿蒙next版开发:相机开发-元数据(ArkTS)
  • 华为机试HJ39 判断两个IP是否属于同一子网
  • MYSQL 库,表 基本操作
  • 网络远程操控
  • 【日志】392.判断子序列
  • GitLab基于Drone搭建持续集成(CI/CD)
  • JavaSE基础50题:11. 输出一个整数的每一位
  • CentOS 7.9 安装 k8s(详细教程)
  • Vue.js实现可编辑表格并高亮修改的单元格
  • 基于remix+metamask+ganache的智能合约部署调用
  • 注解 @Autowired 和 @Resource
  • OpenGL ES 帧缓冲对象介绍和使用示例
  • AI烟火识别智能视频分析系统解决方案
  • Dockerfile详解#如何编写自己的Dockerfile
  • Matlab 用矩阵画图
  • JAVA 多线程并发(一)
  • Jmeter接口测试
  • STL(一)(pair篇)
  • 【Docker二】docker网络模式、网络通信、数据管理
  • Oracle11g RAC无法使用VIP或SCAN IP连接数据库的解决方案
  • 人工智能_机器学习061_KKT条件公式理解_原理深度解析_松弛变量_不等式约束---人工智能工作笔记0101
  • HTTP、HTTPS、SSL协议以及报文讲解
  • 【1day】DocCms 某接口SQL注入漏洞学习
  • Linux:缓冲区的概念理解
  • 什么是HTTPS加密协议? ️
  • Redission分布式锁原理初探