从技术上讲,这是可行的,但有几个注意事项。首先,您正在使用在 React 环境中强烈反对的 DOM。其次,这里发生了很多事情来完成这项工作,如果某些组件、功能或元素在后台发生变化,这确实会让您在未来遇到错误。这里使用了许多元素,但是它们没有正确的 id 或者它们依赖于生成的类名。为了隔离某些元素,您需要通过指定的名称或角色来定位它们……这很脆弱。 (我现在可以告诉你,已经有计划重新设计 sendBox 以适应即将推出的功能。)
在我详细介绍之前,如果您真的想正确执行此操作,我建议您克隆 BotFramework-WebChat repo 并在后台进行自己的更改。这样您就不会直接使用 DOM,如果操作正确,将产生一个更稳定的环境。您有责任使您的版本与官方版本保持同步。无论你走哪条路,你都需要对你的代码进行维护,以使事情保持最新和正常工作。
这应该会让你朝着你想要的方向前进。请注意,这主要集中在网络聊天代码上。除此之外,我没有构建真正的功能。即使是第一个“功能”按钮(见下文),虽然允许您选择文件,但也仅在活动中发送文件名。获取和发送文件以及您的机器人如何响应该活动超出了您的提问范围,因此不会涉及。
辅助函数 - 用于简化创建要使用的不同元素。
const createElement = ( elType, id, className, option ) => {
const el = document.createElement( elType );
switch ( el.localName ) {
case 'button':
if ( id ) {
el.setAttribute( 'id', id );
el.setAttribute( 'type', 'button' );
}
if ( className ) {
el.classList.add( className );
}
return el;
case 'div':
if ( id ) {
el.setAttribute( 'id', id );
}
if (className) {
el.classList.add( className );
}
if (option) {
const style = option.style;
el.setAttribute( 'style', style );
}
return el;
case 'img':
if ( className ) {
el.classList.add( className );
}
if ( option ) {
const src = option;
el.src = src;
}
return el;
case 'input':
if ( id ) {
el.setAttribute( 'id', id );
}
if ( className ) {
el.className = className;
}
if ( option ) {
const inputName = option.name;
const inputType = option.type;
const style = option.style;
el.setAttribute( 'name', inputName );
el.setAttribute( 'type', inputType );
el.setAttribute( 'style', style );
}
return el;
case 'p':
if ( option ) {
const innerText = option;
el.innerText = innerText;
}
return el;
}
};
获取 sendBox - 获取 sendBox 并找到文件附件按钮。
const parent = document.querySelector( '.main' );
const attachmentButton = document.querySelector( '[title="Upload file"]' );
if ( attachmentButton ) {
var attachmentSVG = attachmentButton.firstElementChild;
var attachmentParent = attachmentButton.parentElement;
}
const child = parent.querySelectorAll( 'svg' );
创建菜单和“按钮”(输入) - 注意:第一个按钮documentButton 的功能在于它允许您选择文件。其他五个按钮不起作用,这就是为什么它们的设计与第一个略有不同。 如上所述,在本例中选择文件仅发送文件名。
// Creates containers to hold menu and buttons
const menuContainer = createElement( 'div', 'menuContainer', undefined );
menuContainer.hidden = true;
const firstRow = createElement( 'div', 'firstRow' );
const secondRow = createElement( 'div', 'secondRow' );
const documentButton = createElement( 'div', 'documentBtn', 'menuItemSize', { style: 'display: none' } );
const inputFile = createElement( 'input', 'docFile', 'menuItemSize', { name: 'docFile', type: 'file', style: 'display: none' } );
const docImage = createElement( 'img', undefined, 'menuItemSize', './images/menuDoc.png' );
documentButton.appendChild( inputFile );
documentButton.appendChild( docImage );
const docLabel = createElement( 'p', undefined, undefined, 'Document' );
const docWrapper = createElement( 'div', undefined, 'menuItemWrapper' );
docWrapper.appendChild( documentButton );
docWrapper.appendChild( docImage );
docWrapper.appendChild( docLabel );
firstRow.appendChild( docWrapper );
menuContainer.appendChild( firstRow );
// Enables button, allows file selection, and "sends" file via postBack.
docImage.onclick = () => { inputFile.click() };
inputFile.onchange = ( e ) => { handleChange( e ) };
const handleChange = ( e ) => {
const file = e.target.files[0];
store.dispatch({
type: 'WEB_CHAT/SEND_POST_BACK',
payload: {
value: { file: file.name }
}
})
};
const cameraButton = createElement( 'div', 'cameraBtn', 'menuItemSize' );
const cameraImage = createElement( 'img', undefined, 'menuItemSize', './images/menuCamera.png' );
cameraButton.appendChild( cameraImage );
const cameraLabel = createElement( 'p', undefined, undefined, 'Camera' );
const cameraWrapper = createElement( 'div', undefined, 'menuItemWrapper' );
cameraWrapper.appendChild( cameraButton );
cameraWrapper.appendChild( cameraLabel );
firstRow.appendChild( cameraWrapper );
menuContainer.appendChild( firstRow );
const galleryButton = createElement( 'div', 'galleryBtn', 'menuItemSize' );
const galleryImage = createElement( 'img', undefined, 'menuItemSize', './images/menuGallery.png' );
galleryButton.appendChild( galleryImage);
const galleryLabel = createElement( 'p', undefined, undefined, 'Gallery' );
const galleryWrapper = createElement( 'div', undefined, 'menuItemWrapper' );
galleryWrapper.appendChild( galleryButton );
galleryWrapper.appendChild( galleryLabel );
firstRow.appendChild( galleryWrapper );
menuContainer.appendChild( firstRow );
const audioButton = createElement( 'div', 'audioBtn', 'menuItemSize' );
const audioImage = createElement( 'img', undefined, 'menuItemSize', './images/menuAudio.png' );
audioButton.appendChild( audioImage );
const audioLabel = createElement( 'p', undefined, undefined, 'Audio' );
const audioWrapper = createElement( 'div', undefined, 'menuItemWrapper' );
audioWrapper.appendChild( audioButton );
audioWrapper.appendChild( audioLabel );
secondRow.appendChild( audioWrapper );
menuContainer.appendChild( secondRow );
const locationButton = createElement( 'div', 'locationBtn', 'menuItemSize' );
const locationImage = createElement( 'img', undefined, 'menuItemSize', './images/menuLocation.png' );
locationButton.appendChild( locationImage );
const locationLabel = createElement( 'p', undefined, undefined, 'Location' );
const locationWrapper = createElement( 'div', undefined, 'menuItemWrapper' );
locationWrapper.appendChild( locationButton );
locationWrapper.appendChild( locationLabel );
secondRow.appendChild( locationWrapper );
menuContainer.appendChild( secondRow );
const contactButton = createElement( 'div', 'contactBtn', 'menuItemSize' );
const contactImage = createElement( 'img', undefined, 'menuItemSize', './images/menuContact.png' );
contactButton.appendChild( contactImage );
const contactLabel = createElement( 'p', undefined, undefined, 'Contact' );
const contactWrapper = createElement( 'div', undefined, 'menuItemWrapper' );
contactWrapper.appendChild( contactButton );
contactWrapper.appendChild( contactLabel );
secondRow.appendChild( contactWrapper );
menuContainer.appendChild( secondRow );
let transcriptWindow = document.querySelector( '[dir="ltr"]' );
let fosterParent = createElement( 'div' );
let menuButtonContainer = createElement( 'div', 'menuButtonContainer' );
let menuButton = createElement( 'div', 'menuButton' );
transcriptWindow.appendChild( menuContainer );
按钮功能
// Recreates file attachment button that, when clicked, opens the menu
menuButton.appendChild( attachmentSVG );
menuButtonContainer.appendChild( menuButton );
fosterParent.appendChild( menuButtonContainer );
const buttonDiv = createElement( 'div' );
buttonDiv.classList = attachmentButton.classList
buttonDiv.setAttribute( 'title', 'Upload file' );
buttonDiv.classList.remove( 'webchat__icon-button' );
attachmentButton.remove();
attachmentParent.appendChild( buttonDiv );
buttonDiv.innerHTML = fosterParent.innerHTML;
// Gets elements for use with event listeners
const menuBtnContainer = document.querySelector( '#menuButtonContainer' );
const menuItems = document.querySelectorAll( '.menuItemSize' );
const menuItemButtons = [];
menuItems.forEach(item => {
if ( item.localName === 'div' ) {
menuItemButtons.push( item )
}
});
// Shows/hides menu on file attachment button click
const menu = document.querySelector( '#menuContainer' );
menuBtnContainer.addEventListener('click', ( e ) => {
e.preventDefault();
switch ( menu.hidden ) {
case false:
menu.hidden = true;
break;
case true:
menu.hidden = false;
break;
}
return false;
});
// Hides menu when menu button is clicked
menuItemButtons.map(value => {
value.addEventListener('click', () => {
switch ( value.id ) {
case 'documentBtn':
menu.hidden = true;
break;
}
return false;
})
});
希望有帮助!