鍍金池/ 問答/HTML/ Vue里面的多選反選單選問題

Vue里面的多選反選單選問題

題目描述

完成購物車,完成對(duì)應(yīng)商品的選擇和取消的功能

題目來源及自己的思路

《Vue.js實(shí)戰(zhàn)》第五章

相關(guān)代碼

// 請(qǐng)把代碼文本粘貼到下方(請(qǐng)勿用圖片代替代碼)

<!DOCTYPE html>
<html lang="cmn-hans">

<head>
    <meta charset="utf-8">
    <meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1">
    <!--PC端必選   強(qiáng)制360瀏覽器使用webkit渲染 -->
    <meta name="renderer" content="webkit">
    <!--必選  for PC -->
    <link rel="stylesheet" type="text/css"  href="css.css">
    <title>購物車</title>
</head>

<body>
    <div>
        <p>購物車需求</p>
        <ol>
            <li>展示已經(jīng)加入購物車的商品列表</li>
            <li>商品列表包含商品名稱,商品單價(jià),購買數(shù)量和操作能力</li>
            <li>能夠?qū)崟r(shí)顯示所購買的總價(jià)</li>
            <li>商品數(shù)量可以增加,減少或者直接移除</li>
        </ol>

    </div>
    <hr>
    <!-- 頁面掛載點(diǎn) -->
    <div id="app" v-cloak>
        <template v-if="goods.length">
            <table>
                <thead>
                    <tr>
                        <td>表頭</td>
                        <td>商品名稱</td>
                        <td>商品單價(jià)</td>
                        <td>購買數(shù)量</td>
                        <td>操作</td>
         <td>選擇 | 全選<input type="checkbox" @click="selectAll" id="selectAll" :checked="isCheckedAll"></td>
                    </tr>
                </thead>
                <tbody>
                    <tr v-for="good,index in goods">
                        <td>{{index+1}}</td>
                        <td>{{good.name}}</td>
                        <td>{{good.price}}</td>
                        <!-- 數(shù)量調(diào)整 -->
                        <td>
                            <button @click="reduce(index)" :disabled="good.count === 1">-</button>
                            {{good.count}}
                            <button @click="add(index)">+</button>
                        </td>
                        <!-- 操作 -->
                        <td>
                            <button @click="remove(index)">移除</button>
                        </td>
                        <td>
             <input type="checkbox" @click="select(index,$event)" class="select">
                        </td>
                    </tr>
                </tbody>
            </table>
            <div><p> 全部總價(jià):¥{{totalPrice}}</p>

                    <p>選中總價(jià): ¥{{selectPrice}}</p>

            </div>
        </template>
        <div v-else>購物車是空的</div>
    </div>
    <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
    <script src="trolley.js"></script>
</body>

</html>

css.css:

table {
    border: 1px solid #ccc;
}

thead {
    background-color: #ddd;
}

td {
    border: 1px solid #ccc;
}

trolley.js:

var app = new Vue({
    el: '#app',
    data: {
        //商品數(shù)據(jù)
        goods: [
            { id: 1, name: 'iphone 7', price: 6188, count: 1 },
            { id: 2, name: 'ipad Pro', price: 5888, count: 1 },
            { id: 3, name: 'MacBook Pro', price: 21488, count: 1 }
        ],
        selectPrice: 0,
        isCheckedAll: false ,//初始化沒有全選擇
        isChecked:false
    },
    computed: {
        totalPrice: function() {
            var total = 0;
            for (var i = 0; i < this.goods.length; i++) {
                total += this.goods[i].price * this.goods[i].count;
            }
            return total;
        }
    },
    methods: {
        reduce: function(index) {
            //再次判斷 reduce 減法的可靠性
            if (this.goods[index].count === 1) return;
            this.goods[index].count--;
        },
        add: function(index) {
            this.goods[index].count++;
        },
        remove: function(index) {
            //刪除一條數(shù)組數(shù)據(jù)
            this.goods.splice(index, 1);
        },
        selectAll: function() {
            if (this.isCheckedAll) {

                for (let i = 0; i < this.goods.length; i++) {
                    document.querySelectorAll(".select")[i].checked = false;
                }
            } else {

                for (let i = 0; i < this.goods.length; i++) {
                    document.querySelectorAll(".select")[i].checked = true;
                }
            }
            this.isCheckedAll = !this.isCheckedAll;
        },
        select: function(index, event) {

            if (document.querySelectorAll(".select")[index].checked) {
                document.querySelectorAll(".select")[index].checked = true;

                //逐步全部選中及后續(xù)






            } else {
                document.querySelectorAll(".select")[index].checked = false;


                      //逐步全部不選中及后續(xù)

            }
        }
    },
});

你期待的結(jié)果是什么?實(shí)際看到的錯(cuò)誤信息又是什么?

目前完成了單選和全選功能,但是實(shí)際在操作過程中應(yīng)該在逐個(gè)選中之后,全選按鈕選中,和逐個(gè)取消選中之后,全選按鈕最后也取消選中狀態(tài),沒有完成。
我覺得思路應(yīng)該是每次單選/取消單選的時(shí)候都要循環(huán)判斷全部的checkbox是全部選中/全部不選中,然后再設(shè)置全選按鈕的狀態(tài)。但是不知道應(yīng)該怎么寫。

回答
編輯回答
大濕胸

之前回答別人的問題,Vue 全選 單選問題,

既然用Vue了就操作數(shù)據(jù),盡量不操作DOM。
寫了個(gè)小demo Vue 全選單選問題,右擊查看源碼,可供參考。
<template>
    <div id="app">
        <a  target="_blank">SF上的Vue 全選 單選問題</a>
        <ul>
            <li class="checked-item" @click="singleSelect(row, index)" v-for="(row, index) in goods">
                <input type="checkbox" :checked="row.checked"/>{{row.name}}
            </li>
        </ul>
        <div>
            <span @click="allSelect">
                <input type="checkbox" :checked="isAllSelected"/>
                <button>全選</button>
            </span>
            <span class="checked-count" v-if="checkedGoodIds.length > 0">已選擇:{{checkedGoodIds.length}}項(xiàng)</span>
        </div>
    </div>
</template>
<script>
    new Vue({
        data: {
            goods: [{
                id: 1,
                name: '選項(xiàng)1-xuanyuan1',
                checked: false
            }, {
                id: 2,
                name: '選項(xiàng)2-xuanyuan2',
                checked: false
            }, {
                id: 3,
                name: '選項(xiàng)3-xuanyuan3',
                checked: false
            }, {
                id: 4,
                name: '選項(xiàng)4-xuanyuan4',
                checked: false
            }, {
                id: 5,
                name: '選項(xiàng)5-xuanyuan5',
                checked: false
            }, {
                id: 6,
                name: '選項(xiàng)6-xuanyuan6',
                checked: false
            }],
        },
        computed:{
            // 是否全選
            isAllSelected(){
                return this.goods.every((el) => {
                    return el.checked;
                })
            },
            // 選中商品的id
            checkedGoodIds(){
                let filterArr = this.goods.filter((el) => {
                    return el.checked;
                });
                return filterArr.map((el) => {
                    return el.id;
                })
            }
        },
        methods: {
            // 全選、全不選
            allSelect() {
                let checked = true;
                // 全選
                if(this.isAllSelected){
                    checked = false;
                }
                this.goods = this.goods.map(el => {
                    el.checked = checked;
                    return el;
                })
            },
            // 單選
            singleSelect(row, index) {
                row.checked = !row.checked;
                this.goods.splice(index, 1, row);
            }
        }
    }).$mount('#app')
</script>
2018年5月23日 23:31
編輯回答
醉淸風(fēng)

其他答案提到,需要使用computed,這是正確的,因?yàn)槭欠駃sCheckedAll是需要“實(shí)時(shí)”查看各個(gè)check的值的變化的,故使用computed比較適合。
順便簡(jiǎn)化了一下你的代碼,第一可以將每個(gè)物品的選中與否設(shè)計(jì)成goods的字段,這樣邏輯清楚些;第二 select和selectAll方法重寫了下,以供參考。
代碼如下:

<!DOCTYPE html>
<html lang="cmn-hans">

<head>
  <meta charset="utf-8">
  <meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1">
  <!--PC端必選   強(qiáng)制360瀏覽器使用webkit渲染 -->
  <meta name="renderer" content="webkit">
  <title>購物車</title>
  <style>
    table {
      border: 1px solid #ccc;
    }

    thead {
      background-color: #ddd;
    }

    td {
      border: 1px solid #ccc;
    }

  </style>
</head>

<body>
<div>
  <p>購物車需求</p>
  <ol>
    <li>展示已經(jīng)加入購物車的商品列表</li>
    <li>商品列表包含商品名稱,商品單價(jià),購買數(shù)量和操作能力</li>
    <li>能夠?qū)崟r(shí)顯示所購買的總價(jià)</li>
    <li>商品數(shù)量可以增加,減少或者直接移除</li>
  </ol>

</div>
<hr>
<!-- 頁面掛載點(diǎn) -->
<div id="app" v-cloak>
  <template v-if="goods.length">
    <table>
      <thead>
      <tr>
        <td>表頭</td>
        <td>商品名稱</td>
        <td>商品單價(jià)</td>
        <td>購買數(shù)量</td>
        <td>操作</td>
        <td>選擇 | 全選<input type="checkbox" @click="selectAll" id="selectAll" :checked="isCheckedAll"></td>
      </tr>
      </thead>
      <tbody>
      <tr v-for="good,index in goods">
        <td>{{index+1}}</td>
        <td>{{good.name}}</td>
        <td>{{good.price}}</td>
        <!-- 數(shù)量調(diào)整 -->
        <td>
          <button @click="reduce(index)" :disabled="good.count === 1">-</button>
          {{good.count}}
          <button @click="add(index)">+</button>
        </td>
        <!-- 操作 -->
        <td>
          <button @click="remove(index)">移除</button>
        </td>
        <td>
          <input type="checkbox" @click="select(index)" class="select" :checked="good.isChecked">
        </td>
      </tr>
      </tbody>
    </table>
    <div><p> 全部總價(jià):¥{{totalPrice}}</p>

      <p>選中總價(jià): ¥{{selectPrice}}</p>

    </div>
  </template>
  <div v-else>購物車是空的</div>
</div>
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<script>
  var app = new Vue({
    el: '#app',
    data: {
      //商品數(shù)據(jù)
      goods: [
        { id: 1, name: 'iphone 7', price: 6188, count: 1, isChecked: false },
        { id: 2, name: 'ipad Pro', price: 5888, count: 1, isChecked: false },
        { id: 3, name: 'MacBook Pro', price: 21488, count: 1, isChecked: false }
      ],
      selectPrice: 0,
      isChecked:false
    },
    computed: {
      totalPrice: function() {
        var total = 0;
        for (var i = 0; i < this.goods.length; i++) {
          total += this.goods[i].price * this.goods[i].count;
        }
        return total;
      },
      // 是否全選
      isCheckedAll: function () {
        var flag = true;
        this.goods.forEach(function (item, index) {
          if (!item.isChecked) flag = false;
        })
        return flag;
      }
    },
    methods: {
      reduce: function(index) {
        //再次判斷 reduce 減法的可靠性
        if (this.goods[index].count === 1) return;
        this.goods[index].count--;
      },
      add: function(index) {
        this.goods[index].count++;
      },
      remove: function(index) {
        //刪除一條數(shù)組數(shù)據(jù)
        this.goods.splice(index, 1);
      },
      selectAll: function() {
        this.goods.forEach(function (item, index) {
          item.isChecked = !item.isChecked;
        });
      },
      select: function(index) {
        this.goods[index].isChecked = !this.goods[index].isChecked;
      }
    },
  });
</script>
</body>

</html>
2018年2月22日 17:30
編輯回答
莫小染

用watch或者computed

2018年6月21日 17:49
編輯回答
純妹

給你點(diǎn)個(gè)贊,問題步驟很清晰。
你可以使用watch或者computed監(jiān)聽單選按鈕的state,從而設(shè)置全選按鈕的選中與否。

2017年1月14日 17:47
編輯回答
熊出沒
var app = new Vue({
    el: '#app',
    data: {
        //商品數(shù)據(jù)
        goods: [
            { id: 1, name: 'iphone 7', price: 6188, count: 1 },
            { id: 2, name: 'ipad Pro', price: 5888, count: 1 },
            { id: 3, name: 'MacBook Pro', price: 21488, count: 1 }
        ],
        selectPrice: 0,
        isChecked:false,
        selectedList: []
    },
    computed: {
        totalPrice: function() {
            var total = 0;
            for (var i = 0; i < this.goods.length; i++) {
                total += this.goods[i].price * this.goods[i].count;
            }
            return total;
        },
        isCheckedAll(){
            return this.selectedList.length === this.goods.length
        }
    },
    methods: {
        reduce: function(index) {
            //再次判斷 reduce 減法的可靠性
            if (this.goods[index].count === 1) return;
            this.goods[index].count--;
        },
        add: function(index) {
            this.goods[index].count++;
        },
        remove: function(index) {
            //刪除一條數(shù)組數(shù)據(jù)
            this.goods.splice(index, 1);
        },
        selectAll: function() {
            if (this.isCheckedAll) {

                for (let i = 0; i < this.goods.length; i++) {
                    document.querySelectorAll(".select")[i].checked = false;
                }
                this.selectedList = []
            } else {
                                this.selectedList = []
                for (let i = 0; i < this.goods.length; i++) {
                    document.querySelectorAll(".select")[i].checked = true;
                    this.selectedList.push(i)
                }
            }
        },
        select: function(index, event) {
            let isSelected = document.querySelectorAll(".select")[index].checked
          let selectedIndex = this.selectedList.indexOf(index)
          
          if (isSelected && selectedIndex <= -1) {
                this.selectedList.push(index)
          } else if (!isSelected && selectedIndex > -1){
                this.selectedList.splice(selectedIndex, 1)
          }
        }
    },
});
2017年2月15日 00:16