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

 运行结果:

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

 回车以后更改完成

 更改空白的话弹出提示

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

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
以下是一个Vue商品输入查询案例: HTML代码: ```html <div id="app"> <input type="text" v-model="keyword" placeholder="请输入商品名称"> <button @click="search">搜索</button> <ul> <li v-for="(item, index) in itemList" :key="index">{{ item.name }} - ¥{{ item.price }}</li> </ul> </div> ``` Vue代码: ```javascript new Vue({ el: '#app', data: { keyword: '', itemList: [ { name: '苹果', price: 5.00 }, { name: '香蕉', price: 3.00 }, { name: '橙子', price: 4.00 }, { name: '鸭梨', price: 6.00 }, { name: '芒果', price: 8.00 }, { name: '柚子', price: 5.50 }, { name: '柠檬', price: 4.50 }, { name: '荔枝', price: 10.00 }, { name: '火龙果', price: 15.00 }, { name: '榴莲', price: 20.00 } ] }, methods: { search() { if (this.keyword.trim() !== '') { this.itemList = this.itemList.filter(item => item.name.indexOf(this.keyword) !== -1); } else { this.itemList = [ { name: '苹果', price: 5.00 }, { name: '香蕉', price: 3.00 }, { name: '橙子', price: 4.00 }, { name: '鸭梨', price: 6.00 }, { name: '芒果', price: 8.00 }, { name: '柚子', price: 5.50 }, { name: '柠檬', price: 4.50 }, { name: '荔枝', price: 10.00 }, { name: '火龙果', price: 15.00 }, { name: '榴莲', price: 20.00 } ]; } } } }); ``` 说明: 1. 输入框使用v-model双向绑定数据,实现输入查询功能。 2. 搜索按钮使用@click监听点击事件,当点击搜索按钮时调用search方法。 3. search方法根据输入的关键字筛选商品列表,并重新渲染页面。如果关键字为空,则显示所有商品

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

轨迹_6

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

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

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

打赏作者

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

抵扣说明:

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

余额充值