当不存在时,找不到使用 Vue-Treeselect 添加新项目的方法



我试图创建一个列表下拉菜单,我已经从后端填充。下面是正在讨论的库Vue Treeselect

一旦用户试图输入一些不在里面的东西,我希望能够动态地添加它,然后当请求提交时,在后端创建该值。然而,该库似乎没有提供覆盖默认行为的方法。以下是我到目前为止所做的尝试。

https://codesandbox.io/s/musing-sutherland-i5e8f?fontsize=14& hidenavigation = 1,黑暗主题=

<template>
<div id="app">
<div class="container mt-4 mx-auto">
<treeselect
@search-change="handleSearch"
:multiple="true"
:options="options"
placeholder="Select your favourite(s)..."
no-results-text="No results found... Press enter to add"
v-model="value"
>
</treeselect>
<pre class="bg-gray-200 text-gray-600 rounded mt-4 p-4">{{
JSON.stringify(value, null, 2)
}}</pre>
<h5>Search text: {{ text }}</h5>
<button
@click="appendNewItem"
class="focus:outline-none text-white text-sm py-2.5 px-5 rounded-md bg-blue-500 hover:bg-blue-600 hover:shadow-lg"
>
Add
</button>
</div>
</div>
</template>
<script>
// import the component
import Treeselect from "@riophae/vue-treeselect";
// import the styles
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
export default {
name: "App",
components: {
Treeselect,
},
data() {
return {
lastId: 0,
text: "",
value: [],
options: [
{ id: 1, label: "Option #1" },
{ id: 2, label: "Option #2" },
],
};
},
methods: {
handleSearch(ev) {
this.text = ev;
},
makeId() {
return `new-item-${++this.lastId}`;
},
appendNewItem() {
this.options = [...this.options, { id: this.makeId(), label: this.text }];
},
},
};
</script>

甚至我的按钮解决方案也不起作用,因为一旦您离开树选择输入区域,文本就会重置为空字符串,因此按下按钮会添加空文本。

给定Vue-Treeselect的当前文档,当用户按下enter和树选没有结果时,我如何使它调用我的appendNewItem()函数?

理想情况下,我想这样做:

<treeselect (other-props)>
<template #no-results={ node }>
<span>No results found for {{ node.text }}</span>
<button @click="appendNewItem">Add {{ node.text }}</button>
</template>
</treeselect>

但是,不幸的是,库API不支持这个。而且它仍然不能解决"按enter键时创建新字段"的问题。但无论如何,这将是一个很好的开始。

不得不说,这是一个艰难的选择。

库没有提供一种方法来启用你所描述的功能,但是你可以做的是使用一些底层的Vue api来覆盖库的方法,并尝试达到你需要的效果。

从本质上讲,我们将覆盖库中的select(node)函数,试图使它适应我们的需要。

<script>
import Treeselect from "@riophae/vue-treeselect";
export default {
extends: Treeselect,
data() {
return {
overridesLastNodeId: 0,
};
},
methods: {
overridesFindValue() {
if (this.$refs.control) {
const childRefs = this.$refs.control.$refs;
if (childRefs["value-container"]) {
const valueContainer = childRefs["value-container"];
if (valueContainer.$refs.input) {
return valueContainer.$refs.input.value;
}
}
}
return null;
},
overridesCheckValueInNodes(value) {
let childHasValue = false;
this.traverseAllNodesDFS((node) => {
if (node.label === value) {
childHasValue = true;
}
});
return childHasValue;
},
select(node) {
/**
* Here we override the select(node) method from
* the library, we will inject a new node if a node
* doesn't exist and then proxy this method to the original!
*/
const value = this.overridesFindValue();
if (typeof value === "string" && value.length === 0) {
// This function gets called internally a lot, so we need
// to make sure it's proxied when there is no value
return Treeselect.mixins[0].methods.select.call(this, node);
}
if (value && value !== "") {
if (this.overridesCheckValueInNodes(value)) {
// If there is a value, we just fallback to the default function
this.resetSearchQuery();
return Treeselect.mixins[0].methods.select.call(this, node);
}
}
/**
* Finally, here's the solution to your question.
* We can emit a new node here, call your append function
* sending it the ID and making this work.
*/
const id = `new-node-${++this.overridesLastNodeId}`;
this.$emit("new-node", { value, id });
/**
* Additionally, to make the select select our value
* we need to "emit" it to v-model as well
*/
this.$emit("input", [...this.value, id]);
/**
* Finally, let's reset the input
*/
this.resetSearchQuery();
},
},
};
</script>
然后,记住在代码中使用被覆盖的组件:
<template>
<div class="container mt-4 mx-auto">
<treeselect-extended
:multiple="true"
:options="options"
placeholder="Select your favourite(s)..."
no-results-text="No results found... Press enter to add"
v-model="value"
@new-node="appendNewItem"
/>
<pre class="bg-gray-200 text-gray-600 rounded mt-4 p-4">{{
JSON.stringify(value, null, 2)
}}</pre>
</div>
</template>
<script>
import TreeselectExtended from "./overrides/TreeselectExtended";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
export default {
name: "App",
data() {
return {
value: [],
options: [
{ id: 1, label: "Option #1" },
{ id: 2, label: "Option #2" },
],
};
},
components: {
TreeselectExtended,
},
methods: {
appendNewItem({ value, id }) {
this.options = [...this.options, { id, label: value }];
},
},
};
</script>

这是一个有效的解决方案,但是,我必须建议谨慎使用这段代码,因为它与库的内部实现创建依赖关系!这意味着如果你从package.json更新库,即使是在小版本更新的情况下,你也会给你的项目引入一个突破性的变化!因为这段代码甚至依赖于&;private&;函数,而不仅仅是面向公众的API。你可以尝试未来的证明,但它可能是更明智的选择,只是选择和使用一些不同的库,确实提供了你的需要。

下面是一个Codesandbox,它演示了这一点:

最新更新