【问题标题】:Vue Js range checkbox selection with shiftVue Js范围复选框选择与移位
【发布时间】:2021-01-10 20:48:37
【问题描述】:

我有这个 html:

<div
class="data__file"
v-for="(data, index) in paginatedData"
:key="index"
>
 <label class="data__info" :for="data.idfile" @click="onClickWithShift($event, index)">
   <img
     :src="data.link"
     alt=""
     :class= "{ 'data__image' : 1 ,'data__image-active' : (data.checked === 1) }"
    />
    <input
     v-if="isManager === true"
     type="checkbox"
     class="data__access"
     :value="data.idaccess"
     :checked="(data.checked === 1) ? 1 : null"
     v-model="checkedFilesPermission"      
    />
          
    <input
     v-if="isManager === false"
     type="checkbox"
     class="data__access"
     :value="data.idfile"
     :checked="(data.checked === 1) ? 1 : null"
     v-model="checkedFilesDownload"       
    />
    </label>
</div>

此代码生成复选框输入列表,然后我需要当用户单击带有 shift 的标签时(因为输入是 display:none),单击的输入之间的所有复选框都将被选中或取消选中,就像在此处使用 jquery 一样 How can I shift-select multiple checkboxes like GMail?

但我不知道如何获得它。

非常感谢用户 Spiky Chathu,我按照他说的做了,没有 v-model 也能正常工作,但是当我尝试使用 v-model 时,它不起作用。

这也是我的数据:

data() {
    return {
      isManager: this.$store.getters.isManager,
      checkedFilesPermission: [],
      checkedFilesDownload: [],
      lastCheckedIdx: -1,
      checkedCount: 0,  
      paginatedData: [
        {"link":"images/2020/08/20200803.jpg","idfile":296,"idaccess":2},
        {"link":"images/2020/08/20200807.jpg","idfile":6,"idaccess":99},
        {"link":"images/2020/08/20200812.jpg","idfile":26,"idaccess":29},
        {"link":"images/2020/08/202123.jpg","idfile":960,"idaccess":2919},
        {"link":"images/2020/08/2020032.jpg","idfile":16,"idaccess":9339},
        {"link":"images/2020/08/20200000.jpg","idfile":2,"idaccess":9},
      ]
    };

我认为 VUE 以某种方式阻止输入 v-model 的主要问题

【问题讨论】:

    标签: javascript vue.js


    【解决方案1】:

    这是我刚刚尝试过的东西,似乎可以完成工作

    <template>
      <div>
        <div v-for="(item, index) in items" :key="index">
          <label>
            <input type="checkbox" v-model="item.checked" @click="checked($event, index)">
            {{item.file}}
          </label>
        </div>
        <pre>{{items}}</pre>
    
      </div>
    </template>
    
    <script>
    
    export default {
      data() {
        return {
          lastCheckedIndex: null,
          lastChange: null,
          items: [
            { file: "foo1", idx: 10 },
            { file: "foo2", idx: 20 },
            { file: "foo3", idx: 40 },
            { file: "foo4", idx: 30 },
            { file: "foo5", idx: 10 },
            { file: "foo6", idx: 90 },
            { file: "foo8", idx: 50 },
          ]
        }
      },
      methods: {
        checked(event, index) {
          // wheter or not to the multiple selection
          if (event.shiftKey && (null != this.lastCheckedIndex) && (this.lastCheckedIndex != index)) {
    
            const dir = index > this.lastCheckedIndex ? 1 : -1; // going up or down ?
            const check = this.lastChange;                      // are we checking all or unchecking all ?
    
            for (let i = this.lastCheckedIndex; i != index; i += dir) {
              this.items[i].checked = check;
            }
          }
    
          // save action
          this.lastCheckedIndex = index; 
          this.lastChange = !this.items[index].checked; // onclick is triggered before the default change hence the !
        }
      },
    };
    
    </script>
    

    【讨论】:

      【解决方案2】:

      我想出了解决您问题的方法。我添加了一个模拟对象来重新创建相同的场景,希望你有一个对象数组。


      已编辑:已修改解决方案以满足多个取消选择的情况


      new Vue({
        el: '#app',
        data: {
          paginatedData: [
            {"link":"https://img.icons8.com/list","idfile":296,"idaccess":2},
            {"link":"https://img.icons8.com/list","idfile":6,"idaccess":99},
            {"link":"https://img.icons8.com/list","idfile":26,"idaccess":29},
            {"link":"https://img.icons8.com/list","idfile":960,"idaccess":2919},
            {"link":"https://img.icons8.com/list","idfile":16,"idaccess":9339},
            {"link":"https://img.icons8.com/list","idfile":2,"idaccess":9},
          ],
          lastCheckedIdx: -1,
          checkedFilesPermission : []
        },
        methods: {
          onClickWithShift(event, idx, idFile) {
        
            var action = (this.checkedFilesPermission.indexOf(idFile) === -1) ? 'select' : 'deselect';
            
            if (event.shiftKey && this.lastCheckedIdx !== -1) {
            
              var start = this.lastCheckedIdx;
              var end = idx-1;
              // can select top to bottom or bottom to top
              // always start with lesser value
              if (start > end) {
                start = idx+1;
                end = this.lastCheckedIdx;
              }
              
              for (var c = start; c <= end; c++) {
                var currentIdFile = this.paginatedData[c]['idfile'];
                this.markSelectDeselect(c, action, currentIdFile);
              }
            }
            
            this.markSelectDeselect(idx, action, idFile);
            this.lastCheckedIdx = idx;
            
            if (this.checkedFilesPermission.length === 0) {
              //reset last checked if nothing selected
              this.lastCheckedIdx = -1;
            }
          },
      
          markSelectDeselect(idx, action, idFile) {
            
            var currentPos = this.checkedFilesPermission.indexOf(idFile);
            
            if (action === 'select' && currentPos === -1) {
              this.checkedFilesPermission.push(idFile);
            } else if (action === 'deselect' && currentPos !== -1){
              this.checkedFilesPermission.splice(currentPos, 1);
            }
          }
        }
      })
      <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
      <div id="app">
        <div
            class="data__file"
            v-for="(data, index) in paginatedData"
            :key="index"
        >
            <input
                :id="data.idfile"
                type="checkbox"
                class="data__access"
                :value="data.idfile"
                v-model="checkedFilesPermission"
            />
             <label class="data__info" :for="data.idfile" @click="onClickWithShift($event, index, data.idfile)">
                <img
                    :src="data.link"
                    alt=""
                    :class= "{ 'data__image' : 1 ,'data__image-active' : (checkedFilesPermission.indexOf(data.idfile) !== -1) }"
                />
            </label>
        </div>
      </div>

      您需要单击图像图标才能看到结果,因为您提到输入是隐藏的。我在这里保持可见,以便您可以看到它实际上正在发生变化

      【讨论】:

      • 感谢您的时间和工作,但在我的页面中一切正常,但第一个和最后一个输入之间的复选框没有检查,我认为这是因为我在每个输入上都使用 v-model= “checkedFilesPermission”我用它来知道检查了哪些输入,然后我得到这个数组并将它放在 axios 请求中所以我的代码看起来像 但我认为问题不在于
      • 问题出在data.idFile 吗?因为它不像[1,2,3,4,5] its like [4,1,10,21,8,5]`?
      • 你能用“paginatedData”数据对象和checkedFilesPermission更新你的问题,找出可能是什么问题
      • 我在示例中进行了更改,请您展示如何实现多个取消选择
      • @BigD 当然我可以更改代码以实现多个取消选择。你也可以把你用于 v-model 的“checkedFilesPermission”的代码放进去吗?我需要看看它以找出选择问题
      猜你喜欢
      • 2011-03-10
      • 1970-01-01
      • 2019-01-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-15
      相关资源
      最近更新 更多