众所周知React和Vue经过打包后的input是无法外部赋值的,比如说淘宝的修改地址和h5页面就是这样的。
下面以淘宝为例,来研究研究。
首先登录淘宝进入设置地址页面。

document.querySelector("input[name=post]").value="6666"

直接使用上面代码进行赋值看看,可以发现一点击我们赋值的内容就没有了。
所以我们不能直接赋值,但是我们输入的又有,所以他肯定是在value上做手脚或者在事件上做手脚的

a1.png

通过上图可以看出来他的节点里面设置了get和set属性
我们使用Object.getOwnPropertyDescriptor获取一下他的value信息看看
a2.png

可以看到他的set和get方法的,我们直接使用方法call一下看看

a=document.querySelector("input[name=post]");
Object.getOwnPropertyDescriptor(a,"value").set.call(a,"123456");

可以发现点击之后依然还是消失了,说明不一定是value,估计是在事件上面下功夫!
a3.png

可以看到他自身只绑定了一个事件不符合常理,咱们看一下冒泡事件
一般来说是监听input事件和change事件
a4.png

可以看到冒泡事件中有这2个事件,咱们先设置一下值在触发一下这个事件看看

a=document.querySelector("input[name=post]")
a.value="0000"
event = document.createEvent('HTMLEvents');
event.initEvent('input', true, false);
a.dispatchEvent(event);

直接触发input事件可以看到点击的时候也不存在了,接下来咱们触发一下change事件看看

a=document.querySelector("input[name=post]")
a.value="0000"
event = document.createEvent('HTMLEvents');
event.initEvent('change', true, false);
a.dispatchEvent(event);

直接触发change事件也是不成功的这是怎么回事呢?
别着急,经过我的测试发现了可以设置值的方法,总结如下

function SetValue(node, text) {
    var nodeName = node.nodeName.toLowerCase();
    var event;
    var descriptor;
    if (nodeName === 'input' || nodeName === 'textarea') {
        //获取getter setter
        descriptor = Object.getOwnPropertyDescriptor(node, 'value');
        //删除value的getter和setter并重新赋值
        delete node['value'];
        node.value = text;
        //触发事件以便react和vue内部更改值
        event = document.createEvent('HTMLEvents');
        event.initEvent('propertychange', false, false);
        event.propertyName = 'value';
        node.dispatchEvent(event);
        //必须同时触发,缺一不可
        event = document.createEvent('HTMLEvents');
        event.initEvent('input', true, false);
        node.dispatchEvent(event);
        //重新绑定getter和setter
        if (descriptor) {
            Object.defineProperty(node, 'value', descriptor);
        }
    }
}

总的来说就是通过绑定getter、setter在加上事件辅助来获取值实现的

标签: hack, React和Vue如何使用原生JS赋值

添加新评论