双向绑定
不管是Angular还是Vue,他们的表单的双向绑定无非做了两件事,一件是接收输入的数据并赋值给元素的value属性,一件是监听input
/change
等事件,然后将$event.target.value
赋值给绑定的值。这样就实现了基本的view-model和model-view的双向绑定。
输入+输出===双向绑定
总结为代码就是:
<input [value]="name" (input)="name = $event.target.value" />
在Angular里面:
<input [ngModel]="name" (ngModelChange)="name = $event" />
简写为语法糖的话:
<input [(ngModel)]="name" />
在Vue里面:
<input v-model="form.name"></input>
现在试想,如果我们触发数据改变的方法不是通过用户输入,而是通过在JS里改变,比如下面这样:
html
<input [(ngModel)]="name" id="nameEl"></input>
js:
let element=document.getElementById('nameEl');
element.target.value="xxxxxxx";
现在我们会发现我们绑定的name
变量没有发生改变,原因很简单,我们没有触发任何输出的事件。
我们目前遇到这种场景是因为在拖拽结束的时候,需要改变目标元素的值为我们拖拽的这个元素的内容,这个事情必须在JS里来完成。
拖拽元素
拖拽元素的时候,被拖拽元素会触发以下事件
- dragstart
- drag
- dragend
目标元素会触发以下事件
- dragenter
- dragover
- dragleave
- drop
这个场景只是很多情况中的一个,我们为什么不直接在拖拽结束的时候将value赋值给绑定的变量呢?比如:
source.ondragend = function(evt){
this.name=evt.target.text;
}
因为绑定的这个变量可能没这么简单,他可能是根据数组或者其他数据结构动态渲染出来的,这样我们不太方便直接操作绑定的那个变量。
那我们使用 element.target.value
这种方式,如何才能触发绑定的name
也跟着改变呢。答案是我们可以使用dispatchEvent
派发事件。
什么是dispatchEvent
向一个指定的事件目标派发一个事件, 并以合适的顺序同步调用目标元素相关的事件处理函数。标准事件处理规则(包括事件捕获和可选的冒泡过程)同样适用于通过手动的使用dispatchEvent()方法派发的事件。
现在我们就来实现:
source.ondragstart = function(evt){
ev.dataTransfer.setData("text/plain", ev.target.text);
}
target.ondrop=function(evt){
ev.preventDefault();
const data = ev.dataTransfer.getData("text");
ev.dataTransfer.clearData();
element.target.value=data;
element.dispatchEvent(new Event('input'));
}