Files
im/pages/conversation/chating/components/ChatingFooter/CustomEditor.vue
T
cansnow f49f1f1ad1 17
2025-12-23 00:18:46 +08:00

284 lines
6.2 KiB
Vue

<template>
<div id="editor-container" :call="option" :change:call="editorModule.call"><!-- 编辑器 --></div>
</template>
<script>
export default {
data() {
return {
timer:null,
option:null,
events:[],
}
},
methods: {
insertText(text,successFn,errorFn){
this.addEvent('insertText',text);
},
insertImgEmoji(src,successFn,errorFn){
this.addEvent('insertImgEmoji',src);
},
insertMention(username,userid){
this.addEvent('insertMention',{
username,
userid
});
},
clear(){
this.addEvent('clear');
},
blur(){
this.addEvent('blur');
},
focus(){
this.addEvent('focus');
},
setHtml(html){
this.addEvent('setHtml',html);
},
getText(){
this.addEvent('getText');
},
getHtml(){
console.log(this);
return 1;
this.addEvent('getHtml');
},
getSelectionPosition(){
this.addEvent('getSelectionPosition');
},
getParentNode(){
this.addEvent('getParentNode');
},
// 调用
call() {
if (this.timer) return;
// 消费事件队列(生产者/消费者机制)
this.timer = setInterval(() => {
if (this.events.length) {
this.option = this.events.shift();
console.log(this.option);
} else {
clearInterval(this.timer);
this.timer = null;
}
}, 10);
},
// 添加事件队列
addEvent(name, data) {
// #ifdef APP-PLUS
// tips:由于采用监听option改变来调用方法,
// 如果连续变化两次option,渲染层只会则监听到最后一次
// 导致调用丢失,所以采用事件队列形式解决,稍微延时10ms
// 等待渲染进程监听到option变化,在进行更改option
// 从性能上,几乎无感可以放心使用
const option = {
id: this.genId(),
name: `_${name}`,
data
};
this.events.push(option);
this.call();
// #endif
// #ifndef APP-PLUS
this[`_${name}`] && this[`_${name}`](data);
// #endif
},
genId() {
let result = '';
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
const charactersLength = characters.length;
for (let i = 0; i < 30; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return Date.now() + result;
},
// 开始拖拽地图
UserEvent(data) {
//console.log(data);
this.$emit('onUserEvent',data);
}
}
}
</script>
<script module="editorModule" lang="renderjs">
export default {
data() {
return {
_editorIns:null
}
},
mounted() {
this._initEditor();
},
methods: {
_initEditor() {
if (typeof window.wangEditor === 'function') {
this._initialize();
} else {
const script = document.createElement('script');
script.onload = this._initialize;
script.src = "static/wangeditor/index.js";
document.head.appendChild(script);
const link = document.createElement('link');
link.href = "static/wangeditor/style.css";
link.rel = "stylesheet";
document.head.appendChild(link);
}
},
// 创建地图
_initialize() {
const _this = this;
// 创建地图实例
const {createEditor} = window.wangEditor
const editor = createEditor({
selector: '#editor-container',
html: '',
config: {
placeholder: '',
maxLength:100,
hoverbarKeys:{
divider: {menuKeys: [],},
link: {menuKeys: [],},
image: {menuKeys: [],},
pre: {menuKeys: [],},
table: {menuKeys: [],},
text: {menuKeys: [],},
video: {menuKeys: [],},
},
onCreated(){
_this.$ownerInstance.callMethod('UserEvent',{
type:'ready'
});
},
//onDestroyed(){},
onFocus(){
_this.$ownerInstance.callMethod('UserEvent',{
type:'focus'
});
},
onBlur(){
_this.$ownerInstance.callMethod('UserEvent',{
type:'blur'
});
},
//onDestroyed(){},
onChange(editor) {
const html = editor.getHtml()
const text = editor.getText()
//console.log('editor content', html)
// 也可以同步到 <textarea>
_this.$ownerInstance.callMethod('UserEvent',{
type:'onChange',
html,
text,
});
},
}
});
editor.on('atevent',()=>{
_this.$ownerInstance.callMethod('UserEvent',{
type:'atevent'
});
})
this._editorIns = editor;
console.log(editor.insertText);
this._editorIns.insertText("text");
},
_insertText(text){
console.log('_insertText',text);
this._editorIns.insertText(text);
},
_insertNode(node){
this._editorIns.insertNode(node);
},
_insertImgEmoji(src){
this._insertNode({
type: 'image',
style:{width:'30px',height:'30px'},
src: src,
children: [{text: ''}],
});
},
_insertMention(data){
this._insertNode({
type: 'mention',
username: data.username,
userid: data.userid,
children: [{
text: ''
}],
});
},
_clear(){
this._editorIns.clear();
},
_delete(){
this._editorIns.deleteBackward();
},
_blur(){
this._editorIns.blur();
},
_focus(){
this._editorIns.focus();
},
_setHtml(html){
this._editorIns.setHtml(html);
},
_getText(){
return this._editorIns.getText();
},
_getHtml(){
return this._editorIns.getHtml();
},
_getSelectionPosition(){
return this._editorIns.getSelectionPosition();
},
_getParentNode(){
return this._editorIns.getParentNode();
},
// 通过监听call来调用渲染层方法
call(newValue, oldValue, ownerInstance, instance) {
if(!newValue){
return false;
}
if (this[newValue.name] && typeof this[newValue.name] === "function") {
this[newValue.name](newValue.data);
}
},
}
}
</script>
<style lang="scss" scoped>
.custom_editor {
::v-deep.w-e-text-container{
background: transparent;
[data-slate-editor]{
padding: 0;
}
p,
span{
height: 60rpx;
line-height: 60rpx;
}
p{
white-space: pre-wrap; /* 保留空格 */
margin: 0;
}
img{
}
span{
}
span[data-w-e-type="mention"]{
background-color: #ccc;
margin-right: 10px;
}
}
}
</style>