vue--实现简易版的购物车

目录

1.先搭好页面的基本布局:

2.渲染表格里面的内容

 3.实现全选功能

4.实现数量的加减功能

5.实现点击删除功能

6. 显示总价


在这个案例里我们把表格里面的数据也就是 tr进行封装成一个组件,然后通过 v-for 循环进行重复利用

大致步骤如下:

1.先搭好页面的基本布局:

将头部和尾部部分在 App.vue 里进行基本的搭建

需要单独封装处理的 tr 封装成 MyTr.vue 组件,然后在 App.vue 里进行注册和引入,这里需要注意的是:DOM模板限制, tbody里必须是tr标签, 所以使用组件就得用is属性执行组件名字,因此不能直接像 <MyTr></MyTr> 这样使用

 App.vue,

<template>
  <div>
    <table border="1"
           width="700"
           style="border-collapse: collapse">
      <thead>
        <tr>
          <th>
            <input type="checkbox" />
            <span>全选</span>
          </th>
          <th>名称</th>
          <th>价格</th>
          <th>数量</th>
          <th>总价</th>
          <th>操作</th>
        </tr>
      </thead>
      <tbody>
        <!-- <MyTr></MyTr> -->
        <!-- DOM模板限制, tbody>必须是tr标签, 所以使用组件就得用is属性执行组件名字 -->
        <tr is="MyTr"></tr>
      </tbody>
      <tfoot>
        <tr>
          <td>合计:</td>
          <td colspan="5"></td>
        </tr>
      </tfoot>
    </table>
  </div>
</template>

<script>
import MyTr from './components/MyTr'
export default {
  name: 'App',
  components: {
    MyTr
  },
  data () {
    return {
      goodList: [
        {
          name: "诸葛亮",
          price: 1000,
          num: 1,
          checked: false,
        },
        {
          name: "蔡文姬",
          price: 1500,
          num: 1,
          checked: false,
        },
        {
          name: "妲己",
          price: 2000,
          num: 1,
          checked: false,
        },
        {
          name: "鲁班",
          price: 2200,
          num: 1,
          checked: false,
        },
      ],
    }
  }
}
</script>

MyTr.vue,

<template>
    <tr>
    <td>
      <input type="checkbox" />
    </td>
    <td></td>
    <td></td>
    <td>
      <button>-</button>
      <span></span>
      <button>+</button>
    </td>
    <td></td>
    <td>
      <button>删除</button>
    </td>
  </tr>
</template>

<script>
export default {
  name: 'MyTr'
}
</script>

最后大致的效果如下:

2.渲染表格里面的内容

在 App.vue 里的 tbody 标签的 tr 里通过 v-for 循环,然后需要将对象传给 tr 组件内部也就是 MyTr.vue 里

这里就需要用到组件间的传值--父传子,子类通过 props 进行接收

在提前准备好的 App.vue 里的数据 goodList 里面的 checked 就是用于记录当前的复选框是否处于勾选状态,因此在 MyTr.vue 里的 input 标签里我们需要利用 v-model 进行双向绑定

App.vue

 MyTr.vue

<template>
    <tr>
    <td>
      <input type="checkbox" v-model="obj.checked" />
    </td>
    <td>{{obj.name}}</td>
    <td>{{obj.price}}</td>
    <td>
      <button>-</button>
      <span>{{obj.num}}</span>
      <button>+</button>
    </td>
    <td>{{obj.price * obj.num}}元</td>
    <td>
      <button>删除</button>
    </td>
  </tr>
</template>

<script>
export default {
  name: 'MyTr',
  props: ["obj"],
}
</script>

最后效果如下:

 3.实现全选功能

这里 全选 按钮应该是一个计算属性,因为下面表格里的 小选框 们的状态会直接影响 全选 框

再者当我们选中 全选框 时,页面会把选中的  true/false 状态赋予给 isAll 这个变量,因此这里的 isAll 既要设置又要取值,就需要用到计算属性的完整写法,通过 set() 和 get() 

当在页面点击 全选 复选框后,会把选中状态 true/false 赋予给 v-model 的变量 isAll,这里同时也会影响表格里的 小选框 的状态,而小选框里的状态都在 goodList 数组里的 checked 属性上存着的,因此我们需要做的就是当我们改变 全选框 的状态时就需要更新 goodList 数组

同理当前的这个 isAll 还要来源于我们 goodList 数组里的小选框最后的统计效果

App.vue

  computed: {
    isAll: {
      set(val){ 
        // 页面点击 全选 复选框后,会把选中状态 true/false 赋予给 v-model 的变量
        // 这里的 val 即 isAll,值为 true/false
        this.goodList.forEach(obj => { // 将 true/false 同步给所有小选框的状态值
          obj.checked = val
        });
      },
      get(){
        // every() 该函数所有一项返回true,则返回true。一旦有一项不满足则返回flase
        // 统计小选框的选中状态
        return this.goodList.every(obj => obj.checked == true)
      }
    }
  }

这里需要注意:计算属性里的变量名不能与data里的变量名重名

最后效果如下:

4.实现数量的加减功能

在 MyTr.vue 里给当前的 加减 按钮分别绑定点击事件

MyTr.vue

      <button @click="sub" :disabled="obj.num === 0">-</button>
      
      <button @click="add">+</button>
   
     add(){
      this.obj.num++
    },
    sub(){
      this.obj.num--
    }

最后效果如下:

5.实现点击删除功能

删除 按钮在 MyTr.vue 组件里,当点击 删除 时其实是删除数组里的某个元素,在 MyTr.vue 组件里实现不了,因此当点击 删除 时需要通过 子向父 传值,来通知 App.vue goodList 数组里面将对应下角标对应的对象删除

但是在 MyTr.vue 并没有 goodList 数组里的 索引,实现不了删除,因此需要在 App.vue 里将 index 索引传递给 MyTr.vue ,在 MyTr.vue 通过 props 接收

  • 父: @自定义事件名="父methods函数"

  • 子: this.$emit("自定义事件名", 传值) - 执行父methods里函数代码

App.vue

 

MyTr.vue

 

 

 最后效果如下:

6. 显示总价

统计 goodList 数组里的单价和数量相累计即可得到,因此总价也应该为计算属性

App.vue

  computed: {
        allPrice(){
      /**reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值
       * array.reduce(function(total, currentValue, currentIndex, arr), initialValue)
       * total 	必需。初始值, 或者计算结束后的返回值。
         currentValue 	必需。当前元素
         currentIndex 	可选。当前元素的索引
         arr 	可选。当前元素所属的数组对象。
         initialValue 	可选。传递给函数的初始值
       */
      /**
       * 这里的 0 其实就是第一个参数 sum 的初始值
       * obj 遍历数组里面的每个对象
       */
      return this.goodList.reduce((sum, obj) => {
        if(obj.checked === true){
          sum += obj.price * obj.num
        }
        return sum
      }, 0)
    }
  },

 最后效果如下:

源码:

App.vue

<template>
  <div>
    <table border="1"
           width="700"
           style="border-collapse: collapse">
      <thead>
        <tr>
          <th>
            <input type="checkbox" v-model="isAll" />
            <span>全选</span>
          </th>
          <th>名称</th>
          <th>价格</th>
          <th>数量</th>
          <th>总价</th>
          <th>操作</th>
        </tr>
      </thead>
      <tbody>
        <!-- <MyTr></MyTr> -->
        <!-- DOM模板限制, tbody>必须是tr标签, 所以使用组件就得用is属性执行组件名字 -->
        <tr is="MyTr" v-for="(obj, index) in goodList" :key="index" :obj="obj" :index="index" @sub="subFn"></tr>
      </tbody>
      <tfoot>
        <tr>
          <td>合计:</td>
          <td colspan="5">
            {{allPrice}}
          </td>
        </tr>
      </tfoot>
    </table>
  </div>
</template>

<script>
import MyTr from './components/MyTr'
export default {
  name: 'App',
  components: {
    MyTr
  },
  data () {
    return {
      goodList: [
        {
          name: "诸葛亮",
          price: 1000,
          num: 1,
          checked: false,
        },
        {
          name: "蔡文姬",
          price: 1500,
          num: 1,
          checked: false,
        },
        {
          name: "妲己",
          price: 2000,
          num: 1,
          checked: false,
        },
        {
          name: "鲁班",
          price: 2200,
          num: 1,
          checked: false,
        },
      ],
    }
  },
  computed: {
    isAll: {
      set(val){ 
        // 页面点击 全选 复选框后,会把选中状态 true/false 赋予给 v-model 的变量
        // 这里的 val 即 isAll,值为 true/false
        this.goodList.forEach(obj => { // 将 true/false 同步给所有小选框的状态值
          obj.checked = val
        });
      },
      get(){
        // every() 该函数所有一项返回true,则返回true。一旦有一项不满足则返回flase
        // 统计小选框的选中状态
        return this.goodList.every(obj => obj.checked == true)
      }
    },
    allPrice(){
      /**reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值
       * array.reduce(function(total, currentValue, currentIndex, arr), initialValue)
       * total 	必需。初始值, 或者计算结束后的返回值。
         currentValue 	必需。当前元素
         currentIndex 	可选。当前元素的索引
         arr 	可选。当前元素所属的数组对象。
         initialValue 	可选。传递给函数的初始值
       */
      /**
       * 这里的 0 其实就是第一个参数 sum 的初始值
       * obj 遍历数组里面的每个对象
       */
      return this.goodList.reduce((sum, obj) => {
        if(obj.checked === true){
          sum += obj.price * obj.num
        }
        return sum
      }, 0)
    }
  },
  methods: {
    subFn(index){ // 通过子组件传入 index 删除对应的数据
      this.goodList.splice(index, 1)
    }
  }
}
</script>

MyTr.vue

<template>
    <tr>
    <td>
      <input type="checkbox" v-model="obj.checked" />
    </td>
    <td>{{obj.name}}</td>
    <td>{{obj.price}}</td>
    <td>
      <button @click="sub" :disabled="obj.num === 0">-</button>
      <span>{{obj.num}}</span>
      <button @click="add">+</button>
    </td>
    <td>{{obj.price * obj.num}}元</td>
    <td>
      <button @click="delFn">删除</button>
    </td>
  </tr>
</template>

<script>
export default {
  name: 'MyTr',
  /**
   * obj变量本身是只读的, this.obj = {} 不行的, 
   * 但是你改变obj里的属性值是ok的
   * (而且对象是引用关系, 间接的 影响了外部数组里的对象)
   */
  props: ["obj", "index"],
  methods: {
    add(){
      this.obj.num++
    },
    sub(){
      this.obj.num--
    },
    delFn(){
      this.$emit('sub', this.index)
    }
  }
}
</script>

  • 6
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
vue-element-admin是一个基于Vue.js和Element UI的开源后台管理系统模板。它提供了一套完整的后台管理系统解决方案,包括基础的登录、权限控制、菜单管理、数据展示等功能模块。 vue-element-admin中文版是在vue-element-admin的基础上进行了中文语言的本地化处理,方便中文用户使用和开发。通过使用vue-i18n国际化插件,vue-element-admin中文版能够在页面中进行中文的显示和切换。 vue-element-admin中文版提供了丰富的页面组件和模板,包括表格、表单、图表、地图等,可以快速构建各种类型的后台管理系统。它还提供了可配置的菜单管理模块,方便开发者根据自己的需求进行菜单的添加和调整。 在权限控制方面,vue-element-admin中文版提供了基于角色和路由的权限管理机制。通过配置角色和对应的路由权限,可以实现对用户在系统中的操作权限进行精确控制。 另外,vue-element-admin中文版还集成了常用的工具库和第三方插件,如axios用于进行网络请求,mock.js用于模拟后端接口数据,echarts用于数据可视化等。 总之,vue-element-admin中文版是一个功能强大、易于使用和扩展的后台管理系统模板,可以帮助开发者快速搭建符合自己需求的后台管理系统。无论是初学者还是有经验的开发者,都可以通过vue-element-admin中文版提供的丰富功能和文档资源,轻松构建高质量的后台管理系统。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小白小白从不日白

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

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

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

打赏作者

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

抵扣说明:

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

余额充值