效果展示:(说明:使用webpack重构购物车程序,使用vue-cli生成项目脚手架)
文件结构:
代码:
(1)将原来编写的btn-grp组件单独编写到BtnGrp.vue文件中
-
可以看到现在代码清晰了很多,template标签部分编写模板,script标签部分编写组件的交互代码,编写方式和原先写在HTML的代码一致
-
现在整个前端应用都是基于组件化的,代码变得更加清晰了
<!--vue组件--> <template> <div style="float:right;"> <input class="form-control" v-model="searchProduct" @keyup.enter="filterProduct" type="text" placeholder="请输入商品名称"/> </div> </template> <script type="application/javascript"> // import App from '../App'; export default{ name:"BtnGroup", props:['products'], data:function(){ return { searchProduct:'' } }, methods:{ /* 商品筛选 */ filterProduct:function(){ // console.log(this.$parent.products) var searchArr = []; for(let i=0;i<this.$parent.products.length;i++){ searchArr.push(this.$parent.products[i].name) } var searchIndex = searchArr.indexOf(this.searchProduct); if(searchIndex !== -1){ this.$parent.products = this.$parent.products.filter(function(element, index, self){ /* element数组元素、index元素索引、self数组本身 */ return index == searchIndex; }) }else{ alert('暂无符合商品'); } } } } // module.exports = BtnGroup; // export default BtnGroup; // export default { // props: ['buttons'] // } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <!--翻译:添加“scoped”属性以仅将CSS限制为此组件--> <style type="text/css" scoped> </style>
(2)将原来写在HTML中的代码重构到App.vue中
-
此处因为需要用到BtnGrp组件,所以需要先import 组件,然后在components中引用该组件
<!--主页组件--> <template> <div id="app" class="container"> <h1>购物车</h1> <hr> <!--<BtnGroup v-bind:buttons="buttons"></BtnGroup>--> <div style="overflow: hidden"> <div style="float: left"> <button type="button" v-on:click="addHandler" class="btn btn-primary">添加</button> <button type="button" v-on:click="changeHandler" class="btn btn-default">修改</button> <button type="button" v-on:click="delateHandler" class="btn btn-default">删除</button> </div> <BtnGroup :products="products"></BtnGroup> </div> <br> <br> <table class="table table-bordered table-striped table-hover"> <tr> <td><input type="checkbox" v-on:click="selectAll" name="selectAllBtn" v-model="selectAllState"/></td> <th>ID</th> <th>商品名称</th> <th>商品价格</th> <th>商品数量</th> <th>商品总价</th> </tr> <tr v-for="(product,index) in products"> <td> <input type="checkbox" v-on:click="checkItem(product)" v-model="product.state" name="checkbox" /> </td> <td>{{index+1}}</td> <td>{{product.name}}</td> <td>{{product.price}}</td> <td> <!--可以将两个按钮的方法合成一个,通过传参--> <!--<button @click="changeCount(prod, -1)">-</button>--> <button @click="cutCount(product)" class="btn btn-default btn-sm">-</button> <input type="number" v-model="product.count"/> <!--<button @click="changeCount(prod, 1)">-</button>--> <button @click="addCount(product)" class="btn btn-default btn-sm">+</button> </td> <td>{{product.price * product.count}}</td> </tr> <tr> <!--text-right排版文本右对齐--> <td colspan="5" class="text-right">总价:</td> <!--text-primary辅助类文本--> <td class="text-primary">{{totalMoney}}</td> </tr> </table> </div> </template> <script> /* eslint-disable no-new */ import 'bootstrap/dist/css/bootstrap.min.css' import BtnGroup from './components/BtnGroup' export default{ name: 'App', components: {BtnGroup}, data:function(){ return{ products: [ { name: '小米6S', price: 3999, count: 1, state:false }, { name: '锤子2', price: 4999, count: 1, state:false }, { name: '华为P20', price: 3599, count: 1, state:false }, { name: 'OPPO R15', price: 2999, count: 1, state:false }, { name: 'OPPO R11', price: 1999, count: 1, state:false }, ], selectAllState:false /* 注意:这里修正下,页面里的死数据,操作类的直接写好即可,不用遍历数据获取。 只有页面中的展示信息即动态设置 */ /* buttons:[ {title:'添加',class:'btn-primary',handler:function(){alert('点击添加按钮')}}, {title:'修改',class:'btn-default',handler:function(){alert('点击修改按钮')}}, {title:'删除',class:'btn-default',handler:function(){ for(let i =0;i<app.data().products.length;i++){ // console.log(app.data().products[i].state) if(app.data().products[i].state){ app.data().products.splice(i,1); i--; } }; 全选按钮状态清空 document.querySelectorAll('input[name="selectAllBtn"]')[0].checked = false; }} ] */ } }, methods:{ // 用户点击加减数量时调用 cutCount:function(product){ if(product.count>0){ product.count-- }else{ alert('商品数量不能小于0') } }, addCount:function(product){ product.count++ }, checkItem:function(product){ product.state = !product.state; }, selectAll:function() { var checkObj = document.querySelectorAll('input[name="checkbox"]'); // 获取所有checkbox项 if (event.target.checked) { // 点击全选事件 for (var i = 0; i < checkObj.length; i++) { checkObj[i].checked = true;//选中样式 this.products[i].state = true;//动态改变值,供删除用 } } else { for (var i = 0; i < checkObj.length; i++) { checkObj[i].checked = false; this.products[i].state = false; } } }, /*添加 */ addHandler:function(){ alert("点击添加按钮") }, /* 修改 */ changeHandler:function(){ alert("点击修改按钮") }, /* 删除 */ delateHandler:function(){ for(let i=0;i<this.products.length;i++){ if(this.products[i].state){ this.products.splice(i,1); i--; } } /* 注意:vue里尽量避免DOM操作。所有的操作都是数据驱动 */ this.selectAllState = false;//还原全选按钮状态 } }, computed:{ totalMoney:function(){ var price = 0; for(var i = 0; i < this.products.length; ++i) { price += parseFloat(this.products[i].price * this.products[i].count); } return price; } } } // module.exports = App; // export default app; </script> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>