金山WPS文档在线编辑

背景:vue项目,同一个页面存在多个编辑器场景。

按照往常一样,将编辑器封装成组件然后在页面引入,只能显示最后渲染的一个编辑器,前面渲染的都会消失。尝试过直接用iframe指向文档地址,不用金山提供的jdk还是有一样的问题。

下面是金山的开发给的解决方案:

​​

以下是我根据自己的情况实现的:这个html和需要用到的jdk放在public文件夹中

html 复制代码
// KSIframe.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>www</title>
</head>
<body>
</body>
<script src="./open-jssdk-v0.0.13.umd.js"></script>
<script>
  window.onload = () => {
    const params = new URLSearchParams(window.location.search);
    console.log(params.get('url'), 'url')
    // console.log(params.get('editorId'), 'editorId')
    // console.log(params.get('isShowTopArea'), 'isShowTopArea')
    // console.log(params.get('isShowHeader'), 'isShowHeader')
    // console.log(params.get('isEditable'), 'isEditable')
    const param1 = params.get('url')
    const param2 = params.get('editorId')
    const isEdit = params.get('isEditable') === 'true';
    const isShowTopArea = params.get('isShowTopArea') === 'true';
    const isShowHeader = params.get('isShowHeader') === 'true';
    const url = param1
    let div = document.createElement('div');

    div.setAttribute('id', param2); // 设置iframe的ID
    div.style.height = '520px'
// 将div添加到DOM中
    document.body.appendChild(div); // 添加到body的末尾
    const KSInstance = OpenSDK.config({
      url,
      mount: document.querySelector("#"+param2), // 挂载 iframe 节点
      commandBars: [
        {
          cmbId: 'HeaderMiddle', // 组件 ID
          attributes: {
            enable: isEdit, // 禁用组件(组件显示但不响应点击事件)
          },
        },
      ],
 wordOptions: {
        enableReadOnlyComment: isEdit,
        isBestScale: false, // 打开文档时,默认以最佳比例显示
      },
      commonOptions: {
        isShowTopArea, // 隐藏顶部区域(头部和工具栏)
        isShowHeader, // 隐藏头部区域
        // isBrowserViewFullscreen: false, // 是否在浏览器区域全屏
        // isIframeViewFullscreen: false, // 是否在 iframe 区域内全屏
        // acceptVisualViewportResizeEvent: true, // 控制 WebOffice 是否接受外部的 VisualViewport
      },
    });
 window.addEventListener('message', function(event) {
      // console.log(event.origin, '------>', window.location.origin);
      if (event.origin !== window.location.origin) {
        return; // 只接受来自特定源的消息
      }
      // console.log('Received message:', event.data);
      let getData = event.data
      switch (getData.type) {
        case 'insertEle':
          insertEle(getData.content, getData.markName)
              break;
        case 'setMode':
          setMode(getData.mode);
          break;
        case 'deleteEle':
          deleteEle(getData.key);
          break;
        default:
          console.log('没这个方法')
      }
 // 可以回复消息
      // event.source.postMessage('Hi there!', event.origin);
    }, false);
    async function insertEle(content, markName) {
      await KSInstance.ready();

      const selection = await KSInstance.Application.ActiveDocument.ActiveWindow.Selection

      // 区域对象
      const range = await selection.Range
      const start = await range.Start
      const end = start + content.length
  // 在选区后面插入内容
      await selection.InsertAfter(content)
      // const end = await range.End
      // console.log(range, 'range')
      // console.log(start, 'start1')
      // console.log(end, 'end1')
      await KSInstance.Application.ActiveDocument.Bookmarks.Add({
        Name: markName,
        Range: {
          Start: start,
          End: end
        }
      })
 const marks1 = await KSInstance.Application.ActiveDocument.Bookmarks.Json()
    }
    async function setMode(mode){
      await KSInstance.ready();
      const app = KSInstance.Application
      await app.ActiveDocument.SetReadOnly({
        Value: mode === 'preview'
      })
    }
 async function deleteEle(ceebElemPlaceHolder) {
      await KSInstance.ready();
      const app = KSInstance.Application
      app.ActiveDocument.ReplaceText([
        {
          key: ceebElemPlaceHolder,
          value: ''
        }
      ])
    }

  };
</script>
</html>

文档地址

等初始化需要用到的参数,放在父页面iframe的src中,通过路由参数传递。其它对文档的操作,用iframe通信的方式实现。

javascript 复制代码
 let urlEncoded = encodeURIComponent(fileUrl),
     src = `/KSIframe.html?url=${urlEncoded}&editorId=${this.editorId}&isShowTopArea=${this.isShowTopArea}&isShowHeader=${this.isShowHeader}&isEditable=${this.isEditableFile}`
 this.$nextTick(()=>{
       let box = document.getElementById(this.editorBoxId) // 插入iframe的父元素
       // 移除所有子元素
       box.replaceChildren();
            
       let iframe = document.createElement('iframe')
       iframe.setAttribute('src', src)
       iframe.setAttribute('id', this.editorIframeId)
       iframe.style.height = '500px'
       iframe.style.width = '100%'
       function handleLoaded(){
           let postData = {
               type: 'setMode',
               mode: isPreview ? 'preview' : 'edit'
           }
           iframe.contentWindow.postMessage(postData, window.location.origin);
           this.removeEventListener('load', handleLoaded, false);
       }
       iframe.addEventListener('load', handleLoaded, false);
       box.appendChild(iframe)
 })
      

iframe通信操作文档内容:

javascript 复制代码
let iframe = document.getElementById(this.editorIframeId)
let postData = {
   type: 'deleteEle',
   key: yourKey
}
iframe.contentWindow.postMessage(postData, window.location.origin);


let iframe = document.getElementById(this.editorIframeId)
let postData = {
    type: 'insertEle',
    content,
    markName,
}
iframe.contentWindow.postMessage(postData, window.location.origin);
相关推荐
运维全栈笔记13 小时前
Vue + Spring Boot 前后端分离项目部署笔记(若依 RuoYi-Vue 3.9.2)
运维·服务器·vue.js·spring boot·笔记·开源·开源软件
ly768918 小时前
HTML5 从入门到工程实践:语义化、表单、多媒体、性能与项目规范详解
前端·html·html5
人民广场吃泡面1 天前
前端该重视的编程思想
前端
冬夜戏雪1 天前
agent的trace 和eval
开发语言·前端·javascript
IT_陈寒1 天前
Redis的DEL命令居然没删干净数据?这个坑我爬了半天
前端·人工智能·后端
kyriewen1 天前
面试官让我现场用 AI 改一个真实 bug——他打断我的 3 个理由
前端·面试·ai编程
计算机魔术师1 天前
斯坦福研究:AI 对入门级岗位冲击最大
前端
Simon_He1 天前
一个渲染内核,五个框架包:我的流式 Markdown 渲染库是怎么长成“全家桶”的
前端·vue.js·markdown