[Vue warn]: Unknown custom element: <MyTreeList> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
Гуру Vue.js, подскажите, пожалуйста. Пишу компонент сортируемого дерева элементов (как ни странно, подходящего решения не нашел). И столкнулся с проблемой, которую пока не могу обойти. Часы гугления не помогли.
Струтура компонента такая
MyTree.vue - главный компонентMyTreeList.vue - список элементовMyTreeItem.vue - непосредственно элементMyTreeMixin.jsutils.jsКаждый компонент наследуется от MyTreeMixin.js и имеет свое свойство name, равное названию файла компонента.
В dev режиме (стандартный полный webpack шаблон проекта) ошибка [Vue warn]: Unknown custom element: <MyTreeList> - did you register the component correctly? For recursive components, make sure to provide the "name" option. вылетает через раз. Т.е. сделал правку в MyTreeItem.vue - вебпак пересобрал и с помощью HMR заменил компонент - и компонент отрендерился без ошибок. Внес незначительную правку (просто добавил комментарий или отступ) в MyTreeList.vue - вылезла вышеуказанная ошибка.
// ***********************************************
// MyTreeList.vue
// template
<ul class="tree__list">
<li is="tree-item"
v-for="(treeItem, index) of items"
:key="'index_'+index"
:item="treeItem"
:prevItem="index>0 ? items[index-1] : null"
:isLastChild="index === items.length-1"
:itemLine="getItemLine(index)"
:draggable="draggable"
@item-drag-start="$emit('item-drag-start', $event)"
@load-children="$emit('load-children', $event)"
@input="$emit('input', $event)"
@change-item="$emit('change-item', $event)"
>
<template slot-scope="{ treeNode }">
<slot :treeNode="treeNode">{{ treeNode[stateProps.titleKey] }}</slot>
</template>
</li>
</ul>
// script
import Vue from "vue"
import MyTreeMixin from "./MyTreeMixin.js"
import MyTreeItem from "./MyTreeItem.vue"
import { getCoords, throttle } from "./utils.js"
export default Vue.extend({
name: "My",
mixins: [MyTreeMixin],
components:{
'MyTreeItem': MyTreeItem
},
props:{
list: {
type: Array,
required: true
},
draggable: {
type: Boolean,
default: false
},
},
// ...
})
// ***********************************************
// MyTreeItem.vue
// template
<li class="tree__itemWrap">
<div class="tree__row">
<div class="tree__item">
<div class="tree__content">
<div>
<slot :treeNode="treeItem">
{{ treeItem[stateProps.titleKey] }}
</slot>
</div>
</div>
</div>
</div>
<ul is="MyTreeList"
v-if="hasChildren"
v-show="treeItem.__showChildren"
:list="treeItem.children"
:draggable="draggable"
@item-drag-start="$emit('item-drag-start', $event)"
@load-children="$emit('load-children', $event)"
@input="$emit('input', $event)"
@change-item="$emit('change-item', $event)"
>
<template slot-scope="{ treeNode }">
<slot :treeNode="treeNode">
{{ treeNode[stateProps.titleKey] }}
</slot>
</template>
</ul>
</li>
// script
import Vue from "vue"
import MyTreeMixin from "./MyTreeMixin.js"
import MyTreeList from "./MyTreeList.vue"
import { getCoords, throttle } from "./utils.js"
export default Vue.extend({
name: "MyTreeItem",
mixins: [MyTreeMixin],
components:{
'MyTreeList': MyTreeList
},
props:{
item: {
type: Object,
required: true
},
prevItem: {
type: [Object, null]
},
isLastChild: {
type: Boolean,
default: false
},
itemLine:{
type: String,
default: "once",
validator(value){
return ['once', 'full', 'first','first-child', 'last'].indexOf(value) !== -1
}
},
draggable: {
type: Boolean,
default: false
},
},
computed:{
// ...
treeItem(){
return this.item
}
},
created(){
// инициализируем вотчеры за каждым свойством элемента,
// кроме системных свойств и вложенных элементов
for(const k in this.treeItem){
if(k !== this.childrenKey && k.indexOf("__") !== 0){
this.$watch(`treeItem.${k}`, this.onUpdatedItem)
}
}
},
methods:{
onUpdatedItem(){
// при изменении любого примитивного свойства объекта
// выбрасываем событие с самим элементом
this.$emit('change-item', this._normalizeItem(this.treeItem))
},
},
// ...
})
В остальных файлах нет ничего интересного и влияющего на проблему.
Проблема именно тогда существует, когда структура включает в себя MyTreeList.vue и MyTreeItem.vue. Заметил, что если избавиться от MyTreeItem.vue и всю логику перенести в MyTreeList.vue, то проблемы с вызовом самого себя рекурсивно не возникает.
Но сейчас важно, чтобы каждый элемент списка был отдельным компонентом, т.к. есть вотчеры (watch), следящие за свойствами элемента
Апостиль в Лос-Анджелесе без лишних нервов и бумажной волокиты
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости