Javascript Vue自定义指令使用更新的Dom(或$el)

Javascript Vue自定义指令使用更新的Dom(或$el),javascript,html,vue.js,vuejs2,Javascript,Html,Vue.js,Vuejs2,我想为Dom树中的所有TextNode设计一个自定义指令,将“cx”替换为cx 以下是我到目前为止所做的尝试: Vue.config.productionTip=false 函数removeKeywords(el,关键字){ 如果(!关键字)返回 设n=null 让founds=[] walk=document.createTreeWalker(el,NodeFilter.SHOW_TEXT,null,false) while(n=walk.nextNode()){ 如果(n.textCont

我想为Dom树中的所有TextNode设计一个自定义指令,将“cx”替换为
cx

以下是我到目前为止所做的尝试:

Vue.config.productionTip=false
函数removeKeywords(el,关键字){
如果(!关键字)返回
设n=null
让founds=[]
walk=document.createTreeWalker(el,NodeFilter.SHOW_TEXT,null,false)
while(n=walk.nextNode()){
如果(n.textContent.trim().length<1)继续
创建推送(n)
}
让结果=[]
founds.forEach((项目)=>{
if(新RegExp('cx','ig')。测试(item.textContent)){
让kNode=document.createElement('span'))
kNode.innerHTML=item.textContent.replace(新的RegExp(“(.*?)(cx)(.*?”,“'ig'),“$1$2$3”)
item.parentNode.insertBefore(kNode,item)
item.parentNode.removeChild(项)
}
})
}
让myDirective={}
myDirective.install=函数安装(Vue){
让timeoutIDs={}
Vue.directive('keyword-highlight'{
绑定:函数绑定(el、绑定、vnode){
clearTimeout(timeoutId[binding.value.id])
如果(!binding.value)返回
timeoutIDs[binding.value.id]=setTimeout(()=>{
removeKeywords(el,binding.value.keyword)
}, 500)
},
componentUpdated:函数componentUpdated(el、绑定、vnode){
clearTimeout(timeoutId[binding.value.id])
timeoutIDs[binding.value.id]=setTimeout(()=>{
removeKeywords(el,binding.value.keyword)
}, 500)
}
});
};
Vue.use(myDirective)
app=新Vue({
el:“应用程序”,
数据:{
关键词:“abc”,
关键词1:'xyz'
},
方法:{
}
})
.header{
背景色:红色;
}
强壮的{
背景颜色:黄色
}

测试用例1:尝试将第二个输入更改为任何内容
Test1Test2Test3{{keyword}}{{keyword1}}

测试用例2正在工作 Test1Test2Test3{{keyword}}{{keyword1}}


我不确定这是不是最佳做法,因为有关于修改
vnode
的警告,但这在您的示例中可以动态添加密钥

vnode.key=vnode.elm.innerText
奇怪的是,我注意到第一个指令响应
componentUpdated
,但第二个没有响应,即使第二个内部元素更新了它们的值,但第一个没有响应,这与您所期望的相反

请注意,发生更改是因为当输入更改时,第二个实例再次调用
bind
,而不是因为
componentUpdated
中的代码

console.clear()
Vue.config.productionTip=false
函数removeKeywords(el,关键字){
console.log(el,关键字)
如果(!关键字)返回
设n=null
让founds=[]
walk=document.createTreeWalker(el,NodeFilter.SHOW_TEXT,null,false)
while(n=walk.nextNode()){
如果(n.textContent.trim().length<1)继续
创建推送(n)
}
让结果=[]
founds.forEach((项目)=>{
if(新RegExp('cx','ig')。测试(item.textContent)){
让kNode=document.createElement('span'))
kNode.innerHTML=item.textContent.replace(新的RegExp(“(.*?)(cx)(.*?”,“'ig'),“$1$2$3”)
item.parentNode.insertBefore(kNode,item)
item.parentNode.removeChild(项)
}
})
}
让myDirective={}
myDirective.install=函数安装(Vue){
让timeoutIDs={}
Vue.directive('keyword-highlight'{
绑定:函数绑定(el、绑定、vnode){
console.log('bind',binding.value.id)
clearTimeout(timeoutId[binding.value.id])
如果(!binding.value)返回
vnode.key=vnode.elm.innerText
timeoutIDs[binding.value.id]=setTimeout(()=>{
removeKeywords(el,binding.value.keyword)
}, 500)
},
componentUpdated:函数componentUpdated(el、绑定、vnode){
//clearTimeout(timeoutId[binding.value.id])
//timeoutIDs[binding.value.id]=setTimeout(()=>{
//removeKeywords(el,binding.value.keyword)
//}, 500)
}
});
};
Vue.use(myDirective)
app=新Vue({
el:“应用程序”,
数据:{
关键词:“abc”,
关键词1:'xyz'
},
方法:{
}
})
.header{
背景色:红色;
}
强壮的{
背景颜色:黄色
}

测试用例1:尝试将第二个输入更改为任何内容
Test1Test2Test3{{keyword}}{{keyword1}}

测试用例2正在工作 Test1Test2Test3{{keyword}}{{keyword1}}

我发现Vue用于比较新旧节点,然后生成Dom元素

选中,则第一个元素可以是一个要装入的Dom对象

因此,我按照步骤使用的第三个参数(bind、componentUpdated、update等)生成新的Dom元素,然后将其复制到指令hook的第一个参数

最后,下面的演示似乎奏效了:没有强制重新装载,只有重新编译VNode

PS:我使用deepClone方法克隆
vnode
,因为在函数
\uuuu补丁(oldNode,newNode,hydrating)
内部,它将修改
newNode

PS:如上所述,在指令的钩子中,使用
vnode.context
访问实例

Edit:在
test
下循环所有子项,然后附加到
el
,简单复制
test。innerHTML
el。innerHTML
将导致一些问题,如按钮不工作

然后在我的实际项目中测试这个指令,比如
非常复杂的模板
,到目前为止它运行良好

函数deepClone(vnodes,createElement){
让clonedProperties=['text','isComment','componentOptions','elm','context','ns','isStatic','key']
函数cloneVNode(vnode){
让clonedChildren=vnode.children&&vnode.children.map(cloneVNode)
让cloned=createElement(vnode.tag、vnode.data、clonedChildren)
clonedProperties.forEach(函数(项)