Я работаю над проектом, где использую таблицу 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"><template>
<el-table :data="tableData" style="width: 100%">
<draggable
tag="el-table-header"
:list="visible_columns_new"
:component-data="getComponentData()"
item-key="id"
>
<el-table-column v-for="item in tableColumns" :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>
</draggable>
</el-table>
</template>
<script setup lang="ts">
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 = () => {
return {
wrap: true
}
}
</script></code></pre> <br/> <br/> Как я могу решить эту проблему?
Для того чтобы сделать колонки в таблице 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"><el-table
ref="table"
...
>
...</code></pre> <br/> <pre><code class="javascript">const table = ref();
onMounted(() => {
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>