由于用了框架的原因,用原生js直接賦值是修改不了表單的师脂,或者你肉眼看上去你把表單修改了肛炮,但其實(shí)操作起來(lái)頁(yè)面會(huì)出現(xiàn)問(wèn)題,并且提交表單傳給后端的內(nèi)容其實(shí)并沒(méi)有修改跑揉。因?yàn)橹苯淤x值,vue是監(jiān)聽不到事件的,并不會(huì)修改表單內(nèi)容。react也是同理颠焦。這時(shí)候不能采用直接賦值的方式,而需要使用觸發(fā)事件的方式往枣。由于使用Vue框架不同或者UI框架不同,可能某種js寫法在vue上生效粉渠,但是在react上不生效分冈,只能靠自己去思考嘗試了。場(chǎng)景不一樣霸株,寫的方式也不一樣雕沉,代碼不全,只分享思路去件。本文只針對(duì)自己遇到的情況作以下分享坡椒。
1扰路、輸入框填值
var event = document.createEvent('HTMLEvents');
event.initEvent('input', true, false);
var inputId=document.getElementById('inputId');
inputId.setAttribute('value', '輸入框內(nèi)容');
inputId.dispatchEvent(event);
//也可以使用inputId.dispatchEvent(new Event('input',{bubble:true,"bubbles": true, "cancelable": false})),但是注意倔叼,IE瀏覽器不兼容new Event()
2汗唱、多行文本框填值
var event = document.createEvent('HTMLEvents');
event.initEvent('input', true, false);
var textareaId=document.getElementById('textareaId');
textareaId.innerHTML= '多行文本框內(nèi)容';
textareaId.dispatchEvent(event);
//也可以使用inputId.dispatchEvent(new Event('input',{bubble:true,"bubbles": true, "cancelable": false})),但是注意丈攒,IE瀏覽器不兼容new Event()
3哩罪、下拉框選中填值
var parentSelect = document.getElementById('parentId');
parentSelect.getElementsByClassName('ant-select-selection')[0].click();
//UI渲染需要一定的時(shí)間,獲取動(dòng)態(tài)生成的頁(yè)面需要加一個(gè)宏任務(wù)
setTimeout(function () {
//通過(guò)觀察發(fā)現(xiàn)下拉選擇框的動(dòng)態(tài)生成下拉選項(xiàng)的某個(gè)父級(jí)元素中有個(gè)id屬性是和當(dāng)前這個(gè)下拉選擇框的類ant-select-selection的aria-controls屬性是一一對(duì)應(yīng)的巡验,一樣的际插,所以可以先得到動(dòng)態(tài)生成的下拉選項(xiàng)的id。
var id = document.getElementById('parentId')
.getElementsByClassName('ant-select-selection')[0]
.getAttribute('aria-controls');
//根據(jù)id獲取下拉選項(xiàng)
var li_nodes = document.getElementById(id).getElementsByClassName('ant-select-dropdown-menu-item');
//循環(huán)下拉選項(xiàng)显设,找到傳入的被選中的對(duì)應(yīng)的選項(xiàng)框弛,并觸發(fā)它的click事件
for (var j = 0; j < li_nodes.length; j++) {
var li_ele = li_nodes[j];
var text = li_ele.innerText.replace(/(^\s*)|(\s*$)/g, "");
if (text === "被選中的選項(xiàng)值") {
li_ele.click();
break;
};
};
})
4、單選按鈕選中填值
var parentRadio = document.getElementById('parentRadioID');
var radioNodes = parentRadio.getElementsByClassName('ant-radio-wrapper');//獲取一組單選按鈕集合
var radioArr = [].slice.call(radioNodes, 0);//類數(shù)組轉(zhuǎn)換為數(shù)組
var index = radioArr.findIndex(function (val) {
var text = val.innerText.replace(/(^\s*)|(\s*$)/g, '');
return text === '被選中的選項(xiàng)內(nèi)容';
});
if (~index) {
radioNodes[index].click();
}
5捕捂、日期選中填值
//antd日歷組件為3.X可以用如下方法瑟枫,因?yàn)?.X日歷組件選項(xiàng)有輸入框,4.X沒(méi)有绞蹦,無(wú)法觸發(fā)日歷選項(xiàng)框的input事件去填值力奋,觸發(fā)enter事件去隱藏日歷選項(xiàng)框,這點(diǎn)需要注意幽七。
var event = document.createEvent('HTMLEvents');
event.initEvent('input', true, true);//創(chuàng)建一個(gè)input事件
var eventEnter = document.createEvent('Event');
eventEnter.initEvent('keydown', true, false);
eventEnter = Object.assign(eventEnter, {
ctrlKey: false,
metaKey: false,
altKey: false,
which: 13,
keyCode: 13,
key: 'Enter',
code: 'Enter'
});//創(chuàng)建一個(gè)enter事件
document.getElemntById('dateId').click();//觸發(fā)日期控件input框的點(diǎn)擊事件景殷,為了吧日歷組件顯示出來(lái)
setTimeout(function () {
var ss_input = document.getElementsByClassName('ant-calendar-input')[0];
var len = ss_input.length;
ss_input[0].setAttribute('value', '具體日期' || undefined);
ss_input[0].dispatchEvent(event);
setTimeout(function () {
ss_input[0].dispatchEvent(eventEnter);//觸發(fā)enter事件,讓日歷框選項(xiàng)隱藏
});
});
5澡屡、級(jí)聯(lián)選中填值
上面我都只舉了單個(gè)填值的例子猿挚,這里寫的多個(gè)級(jí)聯(lián)選中框填值的例子,因?yàn)闃I(yè)務(wù)需要驶鹉,表單中可能會(huì)存在多個(gè)級(jí)聯(lián)填值绩蜻,但是這個(gè)和antd的下拉框通過(guò)對(duì)應(yīng)的id去獲取每個(gè)下拉框選項(xiàng)組件不一樣。這個(gè)沒(méi)有id唯一不同的可能就是絕對(duì)定位的高度不一樣室埋。所以我這里是按照順序傳入父級(jí)選項(xiàng)的input框和值办绝,根據(jù)絕對(duì)定位去從小到大排序獲取對(duì)應(yīng)的級(jí)聯(lián)選擇框。然后按照傳入的順序一一對(duì)應(yīng)上值姚淆。日歷的話也可以參考這種思路孕蝉,但是如果日歷的placeholder不一樣也可以根據(jù)placeholder的不同對(duì)應(yīng)上,只要能找到一個(gè)可以唯一對(duì)應(yīng)的標(biāo)識(shí)點(diǎn)即可腌逢。
//遞歸觸發(fā)級(jí)聯(lián)選擇框的點(diǎn)擊事件(因?yàn)槲易约簶I(yè)務(wù)是級(jí)聯(lián)設(shè)置了點(diǎn)擊降淮,如果是hover,就觸發(fā)hover事件)
function menuItemClick(dom, area, index) {
index = index || 0;
if (index > area.length || !area[index]) return;
var parentNodes = dom.querySelectorAll('.ant-cascader-menu')[index];
if (!parentNodes) return;
var nodes = parentNodes.querySelectorAll('.ant-cascader-menu-item')
for (var i = 0; i < nodes.length; i++) {
var text = nodes[i].innerText.replace(/(^\s*)|(\s*$)/g, "");
if (text === area[index]) {
nodes[i].click()
setTimeout(function () {
menuItemClick(dom, area, ++index)
})
}
}
};
function handleCascader(arr) {
for (var i = 0; i < arr.length; i++) {
var parentId = document.getElementById(arr[i].id)
parentId.querySelectorAll('.ant-cascader-input')[0].click()//觸發(fā)父級(jí)級(jí)聯(lián)input框的的點(diǎn)擊事件搏讶,為了讓級(jí)聯(lián)選項(xiàng)框顯示到頁(yè)面上
}
setTimeout(function () {
var parentContents = [].slice.call(document.querySelectorAll('.ant-cascader-menus'));//獲取級(jí)聯(lián)選項(xiàng)框的集合佳鳖,并轉(zhuǎn)換為數(shù)組
//根據(jù)絕對(duì)定位的高度從大到小排序
parentContents.sort(function (a, b) {
return a.offsetTop - b.offsetTop;
})
//執(zhí)行每個(gè)級(jí)聯(lián)的選中對(duì)比填值
for (var i = 0; i < parentContents.length; i++) {
menuItemClick(parentContents[i], arr[i].value);
}
})
};
……省略
//方法調(diào)用霍殴,按從上到下的順序依次傳入
var cascaders=[
{
id: "PermanentAddrCode",
value: ['安徽', '合肥']
},
{
id: "PermanentAddrCode",
value: ['天津', '和平區(qū)']
}
];
handleCascader(cascaders);
6系吩、多選選中填值
var parentSelect = document.getElementById('parentId');
parentSelect.getElementsByClassName('ant-select-selection')[0].click();//觸發(fā)多選組件里面的input框的click事件来庭,為了在dom節(jié)點(diǎn)中獲取多選組件的下拉選項(xiàng)框
var selectedValue = ['被選中的值1','被選中的值2','被選中的值3'] //需要被選中的值
setTimeout(function () {
var id = parentSelect.getElementsByClassName('ant-select-selection')[0]
.getAttribute('aria-controls');//獲取多選組件下拉框選項(xiàng)的id
var li_nodes = document.getElementById(id).getElementsByClassName('ant-select-dropdown-menu-item');//獲取下拉框選項(xiàng)節(jié)點(diǎn)集合
for (var j = 0; j < li_nodes.length; j++) {
var text = li_nodes[j].innerText.replace(/(^\s*)|(\s*$)/g, "");
var index = selectedValue.indexOf(text);//獲取需要被選中的值在節(jié)點(diǎn)集合中的索引
var isSelected = li_nodes[j].className.indexOf('ant-select-dropdown-menu-item-selected');//判斷當(dāng)前節(jié)點(diǎn)是否已經(jīng)被選中
if ((~index && isSelected === -1) || (index === -1 && ~isSelected)) {//當(dāng)前值存在選項(xiàng)中并且未被選中,或者當(dāng)前值已被選中但是當(dāng)前選項(xiàng)中不存在
(
function (num) {
setTimeout(function () {
li_nodes[num].click();
});
}
)(j);//構(gòu)建閉包傳入j
}
};
});
7淑玫、月份組件選中填值
var time="YYYY-MM"http://當(dāng)前被選中的時(shí)間巾腕,到月
var monthId= document.getElementById('monthId');
var monthId_input = monthId.getElementsByTagName('input')[0];
if (!time) {
monthId_input .nextSibling.click();//如果傳入時(shí)間為空,觸發(fā)清空時(shí)間的那個(gè)小圖標(biāo)的click事件
return;
}
monthId_input .click();//觸發(fā)月份組件的input框的click事件
setTimeout(function () {
var date = new Date(time);
var oldYear = date.getFullYear();
var oldMonth = date.getMonth();
var year = document.getElementsByClassName('ant-calendar-month-panel-year-select-content')[0].innerText;
var count = year - oldYear;
var months = document.getElementsByClassName('ant-calendar-month-panel-cell');
var dom = document.getElementsByClassName('ant-calendar-month-panel-' + (count > 0 ? 'prev' : 'next') + '-year-btn')[0];//根據(jù)count大小判斷當(dāng)前傳入時(shí)間是小于還是大于月份組件打開的年份(year)絮蒿,如果大于獲取倒退那個(gè)圖標(biāo)的節(jié)點(diǎn)尊搬,如果小于獲取前進(jìn)那個(gè)圖標(biāo)的節(jié)點(diǎn)
for (var i = 0; i < count; i++) {
setTimeout(function () {
dom.click();//觸發(fā)千金難或者倒退圖標(biāo)的事件,選中傳入時(shí)間的年份
})
}
setTimeout(function () {
months[oldMonth].click();//選中傳入的時(shí)間的月份
})
})
8土涝、其他
有關(guān)event
的了解可以看這篇dispatchEvent 學(xué)習(xí) - 簡(jiǎn)書 (jianshu.com)佛寿。目前就這樣,歡迎指正評(píng)論但壮、交流冀泻。
上面有時(shí)候因?yàn)闉g覽器原因,或者js框架原因等等蜡饵,可能會(huì)有input事件不觸發(fā)弹渔、填值填不上去(有時(shí)候可能是虛假填值,這個(gè)時(shí)候怎么辨別某個(gè)表單選項(xiàng)呢溯祸,可以先聚焦當(dāng)前選項(xiàng)肢专,然后再觸發(fā)該選項(xiàng)失焦事件、如果值還存在焦辅,表示值已經(jīng)填充上去博杖,否則值是沒(méi)填上去的)的情況,這個(gè)時(shí)候可以修改input的事件為冒泡事件筷登,填值如果通過(guò)document.getElementById('inputId').value='輸入框的值'
方式填值不上的話剃根,就采用document.getElementById('inputId').setAttribute('value','輸入框的值')
,在填值不上就采用下面的方式賦值:
function setNativeValue(element, value) {
const { set: valueSetter } = Object.getOwnPropertyDescriptor(element, 'value') || {}
const prototype = Object.getPrototypeOf(element)
const { set: prototypeValueSetter } = Object.getOwnPropertyDescriptor(prototype, 'value') || {}
if (prototypeValueSetter && valueSetter !== prototypeValueSetter) {
prototypeValueSetter.call(element, value)
} else if (valueSetter) {
valueSetter.call(element, value)
} else {
throw new Error('The given element does not have a value setter')
}
}
注意:如果需要兼容IE瀏覽器,原生js盡力別使用es6語(yǔ)法前方,或者如果使用的話狈醉,一定要自己安裝babel相關(guān)
依賴,配置下babel轉(zhuǎn)換規(guī)則,將腳本轉(zhuǎn)換一下惠险,如果要是使用了es7舔糖、es8相關(guān)語(yǔ)法,比如async
await
一定要引入polyfill
,如果是腳手架安裝了莺匠,將js引入也不會(huì)報(bào)錯(cuò),否則在ie上使用會(huì)報(bào)錯(cuò)的十兢。vue
安裝babel-polyfill
,在mian.js引入import 'babel-polyfill';
趣竣;react
安裝react-app-polyfill
,在main.js最上方引入import 'react-app-polyfill/ie11';
import 'react-app-polyfill/stable';