Mortal body, steel heart, with their own strength,
shoulder to shoulder gods。
在对话平台的开发过程中,为了将对话动作列表转化为人可以看得懂的自然语言语句,需要用户输入一些带有占位符的对话模板,比如: 我想定一家位于${ @slots.餐馆位置}的餐馆。这些占位符包含对话全局变量和对话槽位。
当对话比较复杂时,涉及到的变量和槽位会很多。用户在书写模板时需要频繁的跳转到配置页面查看占位符的名称。这样会很低效,也使得对话开发难度变大,大大降低了用户体验。所以需要在用户书写占位符时能够提供智能提示的功能。
项目中是使用element ui 的 autocomplete 组件实现,但是该组件选择动作默认是使用选中的选项替换到input中,而我们需要的是将选中的内容拼接到占位符内容中,而其自带的 select事件回调函数,是在内容更新后触发的,所以这里是有一些坑的, 具体实现是借助了watch来保存更改前的内容,然后 在select内进行拼接。下面是效果:
下面是实现方法
- 组件 template 展现内容:
<!-- 自动补全功能 -->
<div class="ef-autocomplete">
<template v-for="(aInput, aindex) in autoInputs">
<el-autocomplete
class="el-input"
:key="aindex"
v-model="autoInputs[aindex]"
:fetch-suggestions="querySearchAsync"
placeholder="请输入内容"
:trigger-on-focus="false"
@select="((item) => {handleSelect(item, aindex)})">
</el-autocomplete>
</template>
</div>
2. 组件 computed 使用计算属性 同步vuex内容
1.1 intent list
1.2 allSlotname list
1.3 varName list
3. data 内变量
// -------------- 自动补全变量 ----------------------------------
autoInputs: ["",""],
lastAutoInputs:["",""]
4. methods 内添加的函数
// -------------- 测试自动补全功能 ---------------------------------------------------------------
//所有的方法都要写在methods里面
querySearchAsync(queryString, cb) {
// 为 string 添加 startswith 函数
if (typeof String.prototype.startsWith != 'function') {
String.prototype.startsWith = function (prefix) {
return slice(0, prefix.length) === prefix;
}
}
// 为 string 添加 endsWitch 函数
if (typeof String.prototype.endsWith != "function") {
String.prototype.endsWith = function(suffix) {
return this.indexOf(suffix, this.length - suffix.length) !== -1;
}
}
var results = []
if (queryString.endsWith("${@}") || queryString.endsWith("${@")) {
console.log("当前字符串以 ${@} 或 ${@ 结尾")
results.push({"value":"slots"})
results.push({"value":"vars"})
}
if (queryString.endsWith("${@slots.") || queryString.endsWith("${@slots.}")) {
console.log("当前字符串以 ${@slots. 或 ${@slots.} 结尾")
console.log("当前加载到的 slotNameList为: ",this.slotNameList)
results = this.slotNameList.map(slotName=>{
return {"value": slotName}
})
}
if (queryString.endsWith("${@vars.") || queryString.endsWith("${@vars.}")) {
console.log("当前字符串以 ${@vars. 或 ${@vars.} 结尾")
console.log("当前加载到的 varNameList为: ",this.varList)
results = this.varList.map(varName => {
return {"value": varName}
})
}
cb(results)
// clearTimeout(this.timeout);
// this.timeout = setTimeout(() => {
// cb(results);
// }, 1000 * Math.random());
},
// 创建过滤器
createStateFilter(queryString) {
return (program) => {
return (program.value.toLowerCase().indexOf(queryString.toLowerCase()) !== -1);
};
},
// 取值操作 你选中那行,item就就是那那条数据,直接赋值v-modal就实现回显了。
handleSelect(item, index) {
console.log("选中的元素: ", item, "当前的 query: ", this.lastAutoInputs[index])
if (this.lastAutoInputs[index].endsWith("${@") ) {
console.log("当前是以占位符结尾, 替换前 query为: ", this.lastAutoInputs[index])
this.autoInputs[index]= this.lastAutoInputs[index] + item.value + "}"
console.log("当前是以占位符结尾, 替换后 query为: ", this.lastAutoInputs[index])
}
if (this.lastAutoInputs[index].endsWith("${@}") ) {
console.log("当前是以占位符结尾, 替换前 query为: ", this.lastAutoInputs[index])
var queryStrLen = this.lastAutoInputs[index].length
this.autoInputs[index]= this.lastAutoInputs[index].substr(0, queryStrLen-1) + item.value + "}"
console.log("当前是以占位符结尾, 替换后 query为: ", this.lastAutoInputs[index])
}
if (this.lastAutoInputs[index].endsWith("${@vars.") || this.lastAutoInputs[index].endsWith("${@slots.")) {
console.log("当前是以占位符${@vars. 或 ${@slots.结尾, 替换前 query为: ", this.lastAutoInputs[index])
this.autoInputs[index]= this.lastAutoInputs[index] + item.value + "}"
console.log("当前是以占位符${@vars. 或 ${@slots.结尾, 替换后 query为: ", this.lastAutoInputs[index])
}
if (this.lastAutoInputs[index].endsWith("${@vars.}") || this.lastAutoInputs[index].endsWith("${@slots.}")) {
console.log("当前是以占位符${@vars.} 或 ${@slots.}结尾, 替换前 query为: ", this.lastAutoInputs[index])
var queryStrLen = this.lastAutoInputs[index].length
this.autoInputs[index] = this.lastAutoInputs[index].substr(0, queryStrLen-1) + item.value + "}"
console.log("当前是以占位符${@vars.} 或 ${@slots.}结尾, 替换后 query为: ", this.lastAutoInputs[index])
}
},
// ----------------------------------------------------------------------------------------------
5. watch 内监听输入数组
autoInputs: {
handler: function(val, oldVal) {
for (let i = 0; i < val.length; i++) {
if (val[i].indexOf("${@") !== -1) {
this.lastAutoInputs[i] = val[i]
console.log("监听到autoInputs发生改变,且包含${@,将其赋值给 lastAutoInput: ", val[i], this.lastAutoInputs[i])
}
}
},
deep:true, // 配置数组深度监听
}