Mortal body, steel heart, with their own strength, 
shoulder to shoulder gods。



在对话平台的开发过程中,为了将对话动作列表转化为人可以看得懂的自然语言语句,需要用户输入一些带有占位符的对话模板,比如: 我想定一家位于${ @slots.餐馆位置}的餐馆。这些占位符包含对话全局变量和对话槽位。

当对话比较复杂时,涉及到的变量和槽位会很多。用户在书写模板时需要频繁的跳转到配置页面查看占位符的名称。这样会很低效,也使得对话开发难度变大,大大降低了用户体验。所以需要在用户书写占位符时能够提供智能提示的功能。

项目中是使用element ui 的 autocomplete 组件实现,但是该组件选择动作默认是使用选中的选项替换到input中,而我们需要的是将选中的内容拼接到占位符内容中,而其自带的 select事件回调函数,是在内容更新后触发的,所以这里是有一些坑的, 具体实现是借助了watch来保存更改前的内容,然后 在select内进行拼接。下面是效果:




Element 获取字符串_c# string 占位符


Element 获取字符串_elementui 加载中_02


Element 获取字符串_Element 获取字符串_03


下面是实现方法

  1. 组件 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,   // 配置数组深度监听
        }