由于我们项目只需要兼容chrome即可,所以我增加的是chrome的版本判断
参考资料
实现代码:
import * as React from 'react';
export interface ContextMenuInputProps {
className?: string;
value?: string;
type?: string;
spellCheck?: boolean;
placeholder?: string;
onChange?: (value: string) => void;
onClick?: () => void;
onKeyDown?: (e: React.KeyboardEvent<HTMLInputElement>) => void;
onFocus?: () => void;
onBlur?: () => void;
}
export class ContextMenuInput extends React.Component<ContextMenuInputProps, any> {
private inputElement: React.RefObject<HTMLInputElement>;
private menuElement: any;
private selectionStart: number;
private clipTextLen: number;
constructor(props: ContextMenuInputProps) {
super(props);
this.state = {
displayValue: props.value || '',
};
this.inputElement = React.createRef();
this.selectionStart = 0;
this.clipTextLen = 0;
}
public componentWillReceiveProps(nextProps: ContextMenuInputProps) {
if (this.props.value !== nextProps.value) {
this.setState({
displayValue: nextProps.value,
});
}
}
public onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
this.setState({
displayValue: e.target.value,
}, () => {
if (this.props.onChange) {
this.props.onChange(this.state.displayValue);
}
});
}
public onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (this.props.onKeyDown) {
this.props.onKeyDown(e);
}
}
public onClick = () => {
// 光标位置
if (this.inputElement.current) {
this.selectionStart = this.inputElement.current.selectionStart || 0;
}
// 剪切板上字符长度
if (this.hasRightMenu) {
const clipboard = (navigator as any).clipboard;
clipboard.readText().then((clipText: any) => {
this.clipTextLen = clipText.trim().length;
// console.log('clipText.trim().length', clipText.trim().length);
if (this.clipTextLen === 0) {
this.menuElement.style.display = 'none';
}
});
}
if (this.props.onClick) {
this.props.onClick();
}
}
<!--获取当前鼠标点击位置,并将位置赋给自定义右键菜单-->
public customContextMenu = (event: any) => {
event.preventDefault ? event.preventDefault() : (event.returnValue = false);
if (this.hasRightMenu) {
const cstCM = this.menuElement;
cstCM.style.left = event.clientX + 'px';
cstCM.style.top = event.clientY + 'px';
cstCM.style.display = 'block';
<!--点击document 是右键菜单消失-->
document.body.onclick = this.clearCustomCM;
// document.onmousedown = this.clearCustomCM;
}
}
public clearCustomCM = () => {
this.menuElement.style.display = 'none';
document.onmousedown = null;
}
<!--复制-->
public copy = (text: any) => {
(navigator as any).clipboard.writeText(text).then(function () {
// console.log('复制成功');
}, () => {
this.clearCustomCM();
});
}
<!--粘贴-->
public paste = () => {
const clipboard = (navigator as any).clipboard;
clipboard.readText().then((clipText: any) => {
// console.log('clipText' + clipText);
let pasteClipText = clipText.trim();
if (this.selectionStart > 0) {
pasteClipText = this.state.displayValue.slice(0, this.selectionStart) + clipText.trim() + this.state.displayValue.slice(this.selectionStart);
}
this.setState({
displayValue: pasteClipText,
}, () => {
if (this.inputElement.current) {
this.inputElement.current.focus();
}
if (this.props.onChange) {
this.props.onChange(this.state.displayValue);
}
});
}, () => {
this.clearCustomCM();
});
}
<!--判断chrome 浏览器版本号-->
public getChromeVersion = () => {
const arr = navigator.userAgent.split(' ');
let chromeVersion = '';
for (let i = 0; i < arr.length; i++) {
if (/chrome/i.test(arr[i])) {
chromeVersion = arr[i];
}
}
if (chromeVersion) {
return Number(chromeVersion.split('/')[1].split('.')[0]);
} else {
return false;
}
}
<!--浏览器的版本控制自定义右键菜单的显示与否-->
public hasRightMenu = () => {
if (this.getChromeVersion()) {
const version = this.getChromeVersion();
if (version < 66) {
this.menuElement.style.display = 'none';
return false;
}
return true;
} else {
return false;
}
}
public render() {
const { displayValue } = this.state;
const { type, placeholder, className, spellCheck, onFocus, onBlur } = this.props;
return <>
<input
ref={this.inputElement}
type={type}
spellCheck={spellCheck}
className={`${className ? className : ''}`}
value={displayValue}
placeholder={placeholder}
onChange={this.onChange}
onKeyDown={this.onKeyDown}
onClick={this.onClick}
onFocus={onFocus}
onBlur={onBlur}
onContextMenu={this.customContextMenu}
/>
<div ref={node => this.menuElement = node} style={{ position: 'fixed', zIndex: 11111, display: 'none' }}>
<ul>
<li onClick={() => this.copy(displayValue)}>复制<span>ctrl+C</span></li>
<li onClick={() => this.paste()}>粘贴<span>ctrl+V</span></li>
</ul>
</div>
</ >;
}
}