背景:公司的算法工程师训练识别图片中的文字的模型,经常要使用各种开源的图片标注工具(cvat标注工具,OCR标注工具等),我们公司用的cvat标注工具但是老大想要再加些扩展功能方便使用,正常的思路是:从github上拉一份源码,然后修改,然后部署到服务器,完成。但是老大说这个项目目前的更新频率很高,社区很活跃
如果直接改源码可能没两个月,他们更新了一个版本后,他们发布了新功能我们就得重新在新功能上开发扩展功能,所以希望我能写个通用的扩展功能页面,用iframe嵌入他们的开源项目,这样当他们项目有新版本后,我们的扩展工具仍然可以正常使用。 不修改源码开发。。这要怎么做。。当我有的错愕不知所云时,老大给我指了条明路--可以用原生js操作iframe网页中的元素,模拟用户的操作,这样就能不修改源码实现功能了,但是会有跨域的问题,后面做个代理就能解决了
我试了下确实可行,主要就是使用 ref获取到原生 iframe元素,然后使用: iframe.contentWindow.document获取到嵌入网页的document元素,然后就能随心所欲操作其中的dom了
其间碰到一个头疼的问题,就是 用js触发嵌入网页的input元素的value改变后, document.getElementById('input').value = 2 input.value值改变了,但是绑定在上面的 onchange事件却没有执行,后面排查发现是两个原因引起: 1.change 事件必须是先聚焦到input框,后再失去焦点才会触发 2.因为iframe嵌入的网页是用react开发的,react给输入框绑定change事件的写法是:
<input onChang='event => this.setState({val: event.target.value})' value={this.state.val} />
编译打包成js后,它的 change事件并不是直接绑定到 input元素上的
我是使用的f12调试工具发现的,如果是原生input元素写的页面,在事件侦听器中就能看到input元素绑定了change事件,但是用react的方式,事件侦听器中就只绑了个 invalid,而 change事件则可以在它的上级看到,目前还没查到这几个选项是什么作用
后面百度到了一些方法:reactjs-在react js中触发onchange事件的最佳方法是什么 - ITranslater
基本都试了一遍,最后只有下面这种能用:
inp.focus()
triggerInputChange(inp, newVal)
inp.blur()
// const inputTypes = [
// window.HTMLInputElement,
// window.HTMLSelectElement,
// window.HTMLTextAreaElement
// ]
const triggerInputChange = (node, value = '') => {
console.log(node.__proto__.constructor)
// if (inputTypes.indexOf(node.__proto__.constructor) > -1) {
const setValue = Object.getOwnPropertyDescriptor(node.__proto__, 'value').set
const event = new Event('input', { bubbles: true })
setValue.call(node, value)
node.dispatchEvent(event)
// }
}
这样在页面中,通过 iframe.contentWindow.document.getElementById('input') 后,再设置它的 value,change事件就能正常触发了
给大家看下开发后的图片:
最后,我这个需求应该是比较偏的不常见的需求,大家应该不常遇到,也希望大家不要遇到,毕竟哪个公司会让你不改源码开发扩展功能的