vue 商品列表案例

2023-12-13 04:46:28

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')

?运行结果:

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

?回车以后更改完成

?更改空白的话弹出提示

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

文章来源:https://blog.csdn.net/qq_64628470/article/details/134867506
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。