Bootstrap

金山WPS文档在线编辑

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

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

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

​​

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

// 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通信的方式实现。

 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通信操作文档内容:

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);

;