Как сделать колонки в таблице Element Plus перетаскиваемыми?

Я работаю над проектом, где использую таблицу el-table из библиотеки Element Plus в сочетании с draggable для перестановки колонок. Однако у меня возникают ошибки: <br/> Unhandled error during execution of mounted hook <br/> Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'updated'). <br/> <br/> Вот мой код: <br/> <pre><code class="javascript">&lt;template&gt;
    &lt;el-table :data="tableData" style="width: 100%"&gt;
        &lt;draggable
              tag="el-table-header"
              :list="visible_columns_new"
              :component-data="getComponentData()"
              item-key="id"
            &gt;
                &lt;el-table-column v-for="item in tableColumns" :prop="item.prop" :key="item.prop" :label="item.label"&gt;
                     &lt;template #header="scope"&gt; &lt;span style="cursor: move"&gt;⠿&lt;/span&gt; {{ scope.column.label }} &lt;/template&gt;
                     &lt;template #default="scope"&gt; &lt;span&gt;{{ scope.row[item.prop]}}&lt;/span&gt; &lt;/template&gt;
                &lt;/el-table-column&gt;
        &lt;/draggable&gt;
    &lt;/el-table&gt;
&lt;/template&gt;

&lt;script setup lang="ts"&gt;
import { ref } from 'vue'
import draggable from 'vuedraggable'

const tableColumns = [
    { id: 1, prop: 'date',  label: 'Date' },
    { id: 2, prop: 'name',  label: 'Name' },
    { id: 3, prop: 'state',  label: 'State' },
    { id: 4, prop: 'city',  label: 'City' },
]
const tableData = ref([
  {
    date: '2016-05-03',
    name: 'Tom',
    state: 'California',
    city: 'Los Angeles',
  },
])

const getComponentData = () =&gt; {
  return {
    wrap: true
  }
}
&lt;/script&gt;</code></pre> <br/> <br/> Как я могу решить эту проблему?
  • 3 октября 2024 г. 14:14
Ответы на вопрос 2
Для того чтобы сделать колонки в таблице Element Plus перетаскиваемыми с помощью `vuedraggable`, необходимо учитывать, что изменения в порядке колонок должны быть связаны с самим массивом колонок, который хранит их порядок. Также убедитесь, что используете правильную структуру для перетаскивания и правильно передаете необходимые свойства. 

В вашем коде нужно внести несколько изменений:

1. Вам нужно будет отслеживать порядок колонок и обновлять их в массиве `tableColumns`.
2. Поле `:list` у вашего компонента `draggable` должно ссылаться на массив колонок, а не на массив видимых колонок.

Вот исправленный пример вашего кода:

```html
<template>
    <el-table :data="tableData" style="width: 100%">
        <draggable
            tag="template"
            :list="tableColumns"
            item-key="id"
            @end="updateColumns">
            <template v-for="item in tableColumns" :key="item.id">
                <el-table-column
                    :prop="item.prop"
                    :key="item.prop"
                    :label="item.label">
                    <template #header="scope">
                        <span style="cursor: move">⠿</span> {{ scope.column.label }}
                    </template>
                    <template #default="scope">
                        <span>{{ scope.row[item.prop] }}</span>
                    </template>
                </el-table-column>
            </template>
        </draggable>
    </el-table>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import draggable from 'vuedraggable'

const tableColumns = ref([
    { id: 1, prop: 'date', label: 'Date' },
    { id: 2, prop: 'name', label: 'Name' },
    { id: 3, prop: 'state', label: 'State' },
    { id: 4, prop: 'city', label: 'City' },
]);

const tableData = ref([
  {
    date: '2016-05-03',
    name: 'Tom',
    state: 'California',
    city: 'Los Angeles',
  },
]);

const updateColumns = (evt: any) => {
    console.log('Columns reordered:', evt);
    // Теперь вы можете обновить состояние компонентов или выполнить дополнительные действия
}
</script>

<style>
/* Добавьте необходимые стили */
</style>
```

В данной реализации:

- Я изменил `tag` на `template`, чтобы можно было перетаскивать элементы в шаблоне.
- `item-key` принимает свойство `id`, чтобы различать ваши колонки.
- Добавлен метод `updateColumns`, который можно использовать для отслеживания изменений при перетаскивании колонок. Вы можете дописать логику, если нужно обновить состояние.

Убедитесь, что у вас корректно подключен `vuedraggable` и все необходимые зависимости.
<a href="https://element-plus.run/#eyJBcHAudnVlIjoiPHRlbXBsYXRlPlxuICA8ZWwtdGFibGUgOmRhdGE9XCJkYXRhXCIgc3R5bGU9XCJ3aWR0aDogMTAwJVwiIHJlZj1cInRhYmxlXCI+XG4gICAgPGVsLXRhYmxlLWNvbHVtbiB2LWZvcj1cIm4gaW4gY29sdW1uc1wiIHYtYmluZD1cIm5cIiA6a2V5PVwibi5wcm9wXCI+XG4gICAgICA8dGVtcGxhdGUgI2hlYWRlcj1cInNjb3BlXCI+XG4gICAgICAgIDxzcGFuIHN0eWxlPVwiY3Vyc29yOiBtb3ZlXCI+4qC/PC9zcGFuPlxuICAgICAgICB7eyBzY29wZS5jb2x1bW4ubGFiZWwgfX1cbiAgICAgIDwvdGVtcGxhdGU+XG4gICAgPC9lbC10YWJsZS1jb2x1bW4+XG4gIDwvZWwtdGFibGU+XG48L3RlbXBsYXRlPlxuXG48c2NyaXB0IGxhbmc9XCJ0c1wiIHNldHVwPlxuaW1wb3J0IHsgcmVmLCBvbk1vdW50ZWQgfSBmcm9tICd2dWUnO1xuaW1wb3J0IFNvcnRhYmxlIGZyb20gJ3NvcnRhYmxlanMnO1xuXG5jb25zdCB0YWJsZSA9IHJlZigpO1xuXG5jb25zdCBjb2x1bW5zID0gcmVmKFtcbiAgeyBwcm9wOiAgICAgICdpZCcsIGxhYmVsOiAgICAgICAnIycgfSxcbiAgeyBwcm9wOiAgICAnZGF0ZScsIGxhYmVsOiAgICAnRGF0ZScgfSxcbiAgeyBwcm9wOiAgICAnbmFtZScsIGxhYmVsOiAgICAnTmFtZScgfSxcbiAgeyBwcm9wOiAnYWRkcmVzcycsIGxhYmVsOiAnQWRkcmVzcycgfSxcbl0pO1xuXG5jb25zdCBkYXRhID0gcmVmKFtcbiAge1xuICAgIGRhdGU6ICcyMDE2LTA1LTAzJyxcbiAgICBuYW1lOiAnVG9tJyxcbiAgICBhZGRyZXNzOiAnTm8uIDE4OSwgR3JvdmUgU3QsIExvcyBBbmdlbGVzJyxcbiAgfSxcbiAge1xuICAgIGRhdGU6ICcyMDE2LTA1LTAyJyxcbiAgICBuYW1lOiAnVG9tJyxcbiAgICBhZGRyZXNzOiAnTm8uIDE4OSwgR3JvdmUgU3QsIExvcyBBbmdlbGVzJyxcbiAgfSxcbiAge1xuICAgIGRhdGU6ICcyMDE2LTA1LTA0JyxcbiAgICBuYW1lOiAnVG9tJyxcbiAgICBhZGRyZXNzOiAnTm8uIDE4OSwgR3JvdmUgU3QsIExvcyBBbmdlbGVzJyxcbiAgfSxcbiAge1xuICAgIGRhdGU6ICcyMDE2LTA1LTAxJyxcbiAgICBuYW1lOiAnVG9tJyxcbiAgICBhZGRyZXNzOiAnTm8uIDE4OSwgR3JvdmUgU3QsIExvcyBBbmdlbGVzJyxcbiAgfSxcbl0ubWFwKChuLCBpKSA9PiAoeyBpZDogLX5pLCAuLi5uIH0pKSk7XG5cbm9uTW91bnRlZCgoKSA9PiB7IFxuICBuZXcgU29ydGFibGUodGFibGUudmFsdWUuJGVsLnF1ZXJ5U2VsZWN0b3IoJ3RoZWFkIHRyJyksIHtcbiAgICBoYW5kbGU6ICdzcGFuJyxcbiAgICBvbkVuZChlKSB7XG4gICAgICBjb2x1bW5zLnZhbHVlLnNwbGljZShlLm5ld0luZGV4LCAwLCBjb2x1bW5zLnZhbHVlLnNwbGljZShlLm9sZEluZGV4LCAxKVswXSk7XG4gICAgfSxcbiAgfSk7XG59KTtcbjwvc2NyaXB0PlxuIiwiZWxlbWVudC1wbHVzLmpzIjoiaW1wb3J0IEVsZW1lbnRQbHVzIGZyb20gJ2VsZW1lbnQtcGx1cydcbmltcG9ydCB7IGdldEN1cnJlbnRJbnN0YW5jZSB9IGZyb20gJ3Z1ZSdcblxubGV0IGluc3RhbGxlZCA9IGZhbHNlXG5hd2FpdCBsb2FkU3R5bGUoKVxuXG5leHBvcnQgZnVuY3Rpb24gc2V0dXBFbGVtZW50UGx1cygpIHtcbiAgaWYgKGluc3RhbGxlZCkgcmV0dXJuXG4gIGNvbnN0IGluc3RhbmNlID0gZ2V0Q3VycmVudEluc3RhbmNlKClcbiAgaW5zdGFuY2UuYXBwQ29udGV4dC5hcHAudXNlKEVsZW1lbnRQbHVzKVxuICBpbnN0YWxsZWQgPSB0cnVlXG59XG5cbmV4cG9ydCBmdW5jdGlvbiBsb2FkU3R5bGUoKSB7XG4gIGNvbnN0IHN0eWxlcyA9IFsnaHR0cHM6Ly9mYXN0bHkuanNkZWxpdnIubmV0L25wbS9lbGVtZW50LXBsdXNAMi44LjQvZGlzdC9pbmRleC5jc3MnLCAnaHR0cHM6Ly9mYXN0bHkuanNkZWxpdnIubmV0L25wbS9lbGVtZW50LXBsdXNAMi44LjQvdGhlbWUtY2hhbGsvZGFyay9jc3MtdmFycy5jc3MnXS5tYXAoKHN0eWxlKSA9PiB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIGNvbnN0IGxpbmsgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdsaW5rJylcbiAgICAgIGxpbmsucmVsID0gJ3N0eWxlc2hlZXQnXG4gICAgICBsaW5rLmhyZWYgPSBzdHlsZVxuICAgICAgbGluay5hZGRFdmVudExpc3RlbmVyKCdsb2FkJywgcmVzb2x2ZSlcbiAgICAgIGxpbmsuYWRkRXZlbnRMaXN0ZW5lcignZXJyb3InLCByZWplY3QpXG4gICAgICBkb2N1bWVudC5ib2R5LmFwcGVuZChsaW5rKVxuICAgIH0pXG4gIH0pXG4gIHJldHVybiBQcm9taXNlLmFsbFNldHRsZWQoc3R5bGVzKVxufSIsInRzY29uZmlnLmpzb24iOiJ7XG4gIFwiY29tcGlsZXJPcHRpb25zXCI6IHtcbiAgICBcInRhcmdldFwiOiBcIkVTTmV4dFwiLFxuICAgIFwianN4XCI6IFwicHJlc2VydmVcIixcbiAgICBcIm1vZHVsZVwiOiBcIkVTTmV4dFwiLFxuICAgIFwibW9kdWxlUmVzb2x1dGlvblwiOiBcIkJ1bmRsZXJcIixcbiAgICBcInR5cGVzXCI6IFtcImVsZW1lbnQtcGx1cy9nbG9iYWwuZC50c1wiXSxcbiAgICBcImFsbG93SW1wb3J0aW5nVHNFeHRlbnNpb25zXCI6IHRydWUsXG4gICAgXCJhbGxvd0pzXCI6IHRydWUsXG4gICAgXCJjaGVja0pzXCI6IHRydWVcbiAgfSxcbiAgXCJ2dWVDb21waWxlck9wdGlvbnNcIjoge1xuICAgIFwidGFyZ2V0XCI6IDMuM1xuICB9XG59XG4iLCJQbGF5Z3JvdW5kTWFpbi52dWUiOiI8c2NyaXB0IHNldHVwPlxuaW1wb3J0IEFwcCBmcm9tICcuL0FwcC52dWUnXG5pbXBvcnQgeyBzZXR1cEVsZW1lbnRQbHVzIH0gZnJvbSAnLi9lbGVtZW50LXBsdXMuanMnXG5zZXR1cEVsZW1lbnRQbHVzKClcbjwvc2NyaXB0PlxuXG48dGVtcGxhdGU+XG4gIDxBcHAgLz5cbjwvdGVtcGxhdGU+XG4iLCJpbXBvcnQtbWFwLmpzb24iOiJ7XG4gIFwiaW1wb3J0c1wiOiB7XG4gICAgXCJ2dWVcIjogXCJodHRwczovL2Zhc3RseS5qc2RlbGl2ci5uZXQvbnBtL0B2dWUvcnVudGltZS1kb21AMy41LjExL2Rpc3QvcnVudGltZS1kb20uZXNtLWJyb3dzZXIuanNcIixcbiAgICBcIkB2dWUvc2hhcmVkXCI6IFwiaHR0cHM6Ly9mYXN0bHkuanNkZWxpdnIubmV0L25wbS9AdnVlL3NoYXJlZEAzLjUuMTEvZGlzdC9zaGFyZWQuZXNtLWJ1bmRsZXIuanNcIixcbiAgICBcImVsZW1lbnQtcGx1c1wiOiBcImh0dHBzOi8vZmFzdGx5LmpzZGVsaXZyLm5ldC9ucG0vZWxlbWVudC1wbHVzQDIuOC40L2Rpc3QvaW5kZXguZnVsbC5taW4ubWpzXCIsXG4gICAgXCJlbGVtZW50LXBsdXMvXCI6IFwiaHR0cHM6Ly9mYXN0bHkuanNkZWxpdnIubmV0L25wbS9lbGVtZW50LXBsdXNAMi44LjQvXCIsXG4gICAgXCJAZWxlbWVudC1wbHVzL2ljb25zLXZ1ZVwiOiBcImh0dHBzOi8vZmFzdGx5LmpzZGVsaXZyLm5ldC9ucG0vQGVsZW1lbnQtcGx1cy9pY29ucy12dWVAMi9kaXN0L2luZGV4Lm1pbi5qc1wiLFxuICAgIFwic29ydGFibGVqc1wiOiBcImh0dHBzOi8vY2RuLmpzZGVsaXZyLm5ldC9ucG0vc29ydGFibGVqc0AxLjE1LjMvK2VzbVwiXG4gIH0sXG4gIFwic2NvcGVzXCI6IHt9XG59IiwiX28iOnt9fQ==" rel="nofollow">Можно попробовать использовать sortable.js</a> : <br/> <br/> <pre><code class="html">&lt;el-table
  ref="table"
  ...
&gt;
  ...</code></pre> <br/> <pre><code class="javascript">const table = ref();

onMounted(() =&gt; { 
  new Sortable(table.value.$el.querySelector('thead tr'), {
    handle: 'span',
    onEnd(e) {
      columns.value.splice(e.newIndex, 0, columns.value.splice(e.oldIndex, 1)[0]);
    },
  });
});</code></pre>
Похожие вопросы