带有引导程序 vue 的可拖动表

Posted

技术标签:

【中文标题】带有引导程序 vue 的可拖动表【英文标题】:Draggable table with bootstrap vue 【发布时间】:2019-07-07 07:35:42 【问题描述】:

我一直在寻找一种在 Bootstrap Vue 表上拖放行的方法。 我可以在这里找到一个工作版本:Codepen

我已经尝试将此代码实现到我自己的表中:

模板:

<b-table  v-sortable="sortableOptions" @click="(row) => $toast.open(`Clicked $row.item.name`)"  :per-page="perPage" :current-page="currentPage"  striped hover :items="blis" :fields="fields" :filter="filter" :sort-by.sync="sortBy" :sort-desc.sync="sortDesc" :sort-direction="sortDirection" @filtered="onFiltered">
    <template slot="move" slot-scope="row">
        <i class="fa fa-arrows-alt"></i>
    </template>

    <template slot="actions" slot-scope="row">
        <b-btn :href="'/bli/'+row.item.id" variant="light" size="sm" @click.stop="details(cell.item,cell.index,$event.target)"><i class="fa fa-pencil"></i></b-btn>
        <b-btn variant="light" size="sm" @click.stop="details(cell.item,cell.index,$event.target)"><i class="fa fa-trash"></i></b-btn>
    </template>

    <template slot="priority" slot-scope="row">
        <input v-model="row.item.priority" @keyup.enter="row.item.focussed = false; updatePriority(row.item), $emit('update')" @blur="row.item.focussed = false" @focus="row.item.focussed = true" class="form-control" type="number" name="priority" >
    </template>
</b-table>

脚本:

import Buefy from 'buefy';
Vue.use(Buefy);

const createSortable = (el, options, vnode) => 

    return Sortable.create(el, 
    ...options
    );
;

const sortable = 
    name: 'sortable',
    bind(el, binding, vnode) 
    const table = el.querySelector('table');
    table._sortable = createSortable(table.querySelector('tbody'), binding.value, vnode);
    
;
export default 
    name: 'ExampleComponent',
    directives:  sortable ,
    data() 
        let self = this;
        return 
            blis: [],
            currentPage: 1,
            perPage: 10,
            pageOptions: [ 5, 10, 15 ],
            totalRows: 0,
            sortBy: null,
            sortDesc: false,
            sortDirection: 'asc',
            sortableOptions: 
                chosenClass: 'is-selected'
            ,
            filter: null,
            modalInfo:  title: 'Title', content: 'priority' ,
            fields: [ 
                
                    key: 'move',
                    sortable: true
                ,
                ///...rest of the fields
            ]
    
;

现在我收到了这个错误:指令可排序绑定挂钩中的错误:“TypeError: Cannot read property 'querySelector' of null”

为什么找不到&lt;tbody&gt;

编辑:https://jsfiddle.net/d7jqtkon/

【问题讨论】:

您可以为您的箱子制作小提琴或钢笔吗?可能是queySelector 无法读取,因为tbody 不可用尝试在document.addEventListener('DOMContentLoaded',function() ); 中添加代码 我遇到了同样的错误jsfiddle.net/d7jqtkon@karthickj25 【参考方案1】:

const table = el.querySelector('table'); 行中,您正在尝试获取表格元素。 var el 是表格元素。这就是为什么当你使用 querySelector 时它返回 null

分配正确的表变量后,错误消失

  const table = el;    
  table._sortable = createSortable(table.querySelector("tbody"), binding.value, vnode);

Link to working fiddle

【讨论】:

这实际上是有道理的。感谢您的帮助,它现在可以正常工作了。 :-) @karthickj25 我也尝试过这个解决方案,但我收到一个错误,因为我的脚本不知道来自return Sortable.create 的标签Sortable 然后使用npm install sortablejs 安装Sortable 并在您的app.js 或任何作为vue js 项目入口文件的文件中导入import Sortable from 'sortablejs'。你可以在这里找到官方文档link。【参考方案2】:

new Vue(
  el: "#app",
    directives: 
    sortable: 
      bind(el, binding, vnode) 
        let self =el
        Sortable.create(el.querySelector('tbody'),
          ...binding.value,
          vnode:vnode,
          onEnd: (e) =>  
            let ids = el.querySelectorAll("span[id^=paper_]")
            let order = []
            for (let i = 0; i < ids.length; i++) 
              let item = JSON.parse(ids[i].getAttribute('values'))
              //extract items checkbox onChange v-model
              let itemInThisData = vnode.context.items.filter(i => i.id==item.id)
              order.push(
                id:item.id,
                paper: item.paper,
                domain:item.domain,
                platform: item.platform,
                country:item.country,
                sort_priority: item.sort_priority,
                selectpaper:itemInThisData[0].selectpaper
              )
            
            binding.value = []
            vnode.context.items = []
            binding.value = order
            vnode.context.items = order
            console.table(vnode.context.items)
          ,
        );
      ,    
    
  ,
  mounted() 
    this.totalRows = this.items?this.items.length: 0
  ,
  methods:
    onFiltered(filteredItems) 
      // Trigger pagination to update the number of buttons/pages due to filtering
      this.totalRows = filteredItems.length
      this.currentPage = 1
    ,
    log()
      console.table(this.items)
      console.log(this)
    ,
  ,
  data()
    return 
    rankOption:'default',
    totalRows: 1,
    currentPage: 1,
    filter: null,
    filterOn:[],
    sortBy:'paper',
    sortDesc: false,
    sortableOptions: 
      chosenClass: 'is-selected'
    ,
    perPage: this.results_per_page==='Todo' ? this.items.length : this.results_per_page?this.results_per_page:50,
    pageOptions: [10, 50, 100, 500,'Todo'],
    sortDirection: 'asc',
    fields : [
       key: 'paper', label: 'Soporte', sortable: true,
       key: 'domain', label: 'Dominio', sortable: true,
       key: 'platform', label: 'Medio', sortable: true,
       key: 'country', label: 'País', sortable: true,
       key: 'sort_priority', label: 'Rank', sortable: true,
       key: 'selectpaper', label: 'Selección', sortable: true,
    ],
    items : [
      
        id:12,
        paper: 'Expansion',
        domain:'expansion.com',
        platform: 'p',
        country:'España',
        sort_priority: '',
        selectpaper:false
      ,
      
        id:13,
        paper: 'El economista',
        domain:'eleconomista.es',
        platform: 'p',
        country:'España',
        sort_priority: '',
        selectpaper:false
      ,
      
        id:14,
        paper: 'El país',
        domain:'elpais.es',
        platform: 'p',
        country:'España',
        sort_priority: '',
        selectpaper:false
      
    ]
  
    
)
<div id="app">
<template id="">
  <b-table
  :sort-by.sync="sortBy"
  :sort-desc.sync="sortDesc"
  v-sortable="items"
  show-empty
  small
  stacked="md"
  :items="items"
  :fields="fields"
  :current-page="currentPage"
  :per-page="perPage"
  :filter="filter"
  :filterIncludedFields="filterOn"
  :sort-direction="sortDirection"
  @filtered="onFiltered"
  >
  <template v-slot:cell(selectpaper)="row">
    <span :id="'paper_'+row.item.id" :values="JSON.stringify(row.item)"></span>
    <b-form-group>
      <input  type="checkbox" @change="log" v-model="row.item.selectpaper" />
    </b-form-group>
  </template>
  <template v-slot:cell(sort_priority)="row" v-if="rankOption==='foreach-row'">
    <b-form-group>
      <b-form-input type="number"  @change="log"
      size="sm" placeholder="Rank" v-model="row.item.sort_priority">
    </b-form-input>
  </b-form-group>
  </template>
  </b-table>
</template>
</div>
<script src="//unpkg.com/vue@latest/dist/vue.min.js"></script>
<script src="//unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js"></script>

【讨论】:

以上是关于带有引导程序 vue 的可拖动表的主要内容,如果未能解决你的问题,请参考以下文章

带有 vue js 组件的轮播引导程序

带有引导程序或 Vuetify 的 Vue CLI 4

带有引导程序的 JavaScript 表过滤器

Vue js引导程序在折叠时添加动画

如何在单击引导模式时获取引导表行值

如何使用 angularJS 将可拖动指令应用于引导模式?