【问题标题】:Editable WKWebView可编辑的 WKWebView
【发布时间】:2021-07-23 15:35:43
【问题描述】:

我在 WKWebView 中显示 .html 和 .xml 文件。 我正在连接所有数据并在 WKWevView 中显示以下字符串

sourceWebView.loadHTMLString(sourceHtmlStr, baseURL: nil)

在加载内容后,即在

webView(_ webView: WKWebView, didFinish 导航: WKNavigation!){}

singleWebView.evaluateJavaScript("document.body.setAttribute('contentEditable','true')") { (anyObj: Any?, error: Error?) in
   if anyObj != nil{
       print("AnyObj in jave script : \(anyObj!)")
   }
   if error != nil{
       print("Error in Java script : \(error!)")
   }
}

以上代码使 WKWebView 成为可编辑的。但我不确定如何保存编辑后的值。 我关注了Link并使用了下面的代码

我在 .js 文件中有以下代码

var richeditor = {};
var editor = document.getElementById("editor");

richeditor.insertText = function(text) {
    editor.innerHTML = text;
    window.webkit.messageHandlers.heightDidChange.postMessage(document.body.offsetHeight);
}

editor.addEventListener("input", function() {
    window.webkit.messageHandlers.textDidChange.postMessage(editor.innerHTML);
}, false)

document.addEventListener("selectionchange", function() {
    window.webkit.messageHandlers.heightDidChange.postMessage(document.body.offsetHeight);
}, false);

在 WindowDidLoad 中:

guard let scriptPath = Bundle.main.path(forResource: "RichTextEditor", ofType: "js"),
   let scriptContent = try? String(contentsOfFile: scriptPath, encoding: String.Encoding.utf8)
else {
   print("Unable to find javscript for text editor")
   return
}
singleWebView.configuration.userContentController.addUserScript(WKUserScript(source: scriptContent, injectionTime: .atDocumentEnd, forMainFrameOnly: true))

let configuration = singleWebView.configuration
[ShowPreviewWindowContoller.textDidChange, ShowPreviewWindowContoller.heightDidChange].forEach {
   configuration.userContentController.add(WeakScriptMessageHandler(delegate: self), name: $0)
}

并添加以下方法:

func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
   switch message.name {
   case ShowPreviewWindowContoller.textDidChange:
       guard let body = message.body as? String else { return }
       delegate?.textDidChange(text: body)
   case ShowPreviewWindowContoller.heightDidChange:
       guard let height = message.body as? CGFloat else { return }
       self.height = height > ShowPreviewWindowContoller.defaultHeight ? height + 30 : ShowPreviewWindowContoller.defaultHeight
       delegate?.heightDidChange()
    default:
       break
    }
}

这种实现方式是不保存编辑过的数据。

这里还要注意的是,我的 html 字符串中没有“编辑器”元素。 我不太确定 html 字符串的所有元素是什么,因为文件不是一个常量,元素可以是任何东西。

抱歉,问题太长了。 请让我知道如何实现这一点。 编辑 WKWebView,将编辑后的文本保存回来。 我也会有很多像下面这样的字符串,我需要确保我替换成确切的元素

<trans-unit id="0000000006" datatype="x-text/xml" restype="string">
    <target>Some Text here</target>
</trans-unit>
<trans-unit id="0000000007" datatype="x-text/xml" restype="string">
    <target>Some Text here</target>
</trans-unit>

我正在使用下面的 HTML 字符串,请注意我对 html 没有任何控制,我会显示用户选择的内容。

编辑:添加修改后的 htmlstring

<!doctype html>\n
<html>
   \n
   <head>
      \n
      <meta charset=\"UTF-8\">
      \n<meta name=\"description\" content=\"AppleCare Training authored this course. If you use this course outside the AppleCare Training site, give credit to its author.\">\n<!-- If you are using an interaction to mark the page complete or if it is an AA page, change mark_complete to false -->\n
      <meta name=\"template_version\" content=\"01.05.2015\">
      \n
      <meta name=\"page\" content=\" \" mark_complete=\"false\">
      \n
      <link href=\"https://idesk.corp.apple.com/training/ce/_common/css/sgt.css\" media=\"screen, projection\" rel=\"stylesheet\" type=\"text/css\"/>
      \n<script>\n\tvar url = window.location.href;\n\tvar filename = \"\";\n\tvar is_local = url.substr(0,4);\n\tif(is_local==\"file\" || window.location.hostname === \"localhost\"){\n\t\t//Local Common Folder Location\n\t\tdocument.write(\'\\x3Cscript type=\"text/javascript\" src=\"http://localhost/_common/js/jquery.js\">\\x3C/script>\');\n\t\tdocument.write(\'\\x3Cscript type=\"text/javascript\" src=\"http://localhost/_common/js/ready.js\">\\x3C/script>\');\n\t}else{\n\t\tdocument.write(\'\\x3Cscript type=\"text/javascript\" src=\"/training/ce/_common/js/jquery.js\">\\x3C/script>\');\n\t\tdocument.write(\'\\x3Cscript type=\"text/javascript\" src=\"/training/ce/_common/js/ready.js\">\\x3C/script>\');\n\t}\n</script>\n\n
      <title>
         <target id=2>Key Terms and Concepts</target>
      </title>
      \n
   </head>
   \n\n
   <body class=\"aa\">
      \n\n\t\t\t<!-- BEGIN PAGE CONTENT -->\n\t
      <div id=\"maincontent\">
         \n
         <div id=\"learningcontentdiv\">
            \n
            <div id=\"morelearningcontentdiv\"></div>
            \n
         </div>
         \n\t\t\t  
         <div id=\"content\">
            \n
            <div id=\"close_aa_term\">
               <target id=4>×</target>
            </div>
            \n
            <h2>
               <target id=6>Key Terms and Concepts</target>
            </h2>
            \n
            <p>
               <target id=8>You should already be familiar with all the terms in this module.</target>
               \t  
            </p>
            \n\t  
         </div>
         \n
      </div>
      \n\n<!-- END PAGE CONTENT -->\n
   </body>
   \n
</html>

【问题讨论】:

  • 这个问题是同一个问题吗? WKWebView editable with .xlf, .html files
  • @Willeke ,是的,我投票删除了另一个问题。我在这里提供了更多信息。
  • 另一个问题已经有了答案和赏金。请编辑其他问题并删除此问题。
  • @Willeke ,我已经将另一个标记为删除,恐怕如果我标记此删除,那么我的两个问题都会被删除。不确定它在堆栈溢出中是如何工作的。
  • @Willeke 我关闭了另一个问题,仅供参考,我向试图帮助我的人提供了赏金。

标签: swift macos cocoa wkwebview


【解决方案1】:

尝试使用此示例代码按预期工作。

class ViewController: UIViewController, WKScriptMessageHandler {

var htmlString = """

<!doctype html>\n
<html>
   \n
   <head>
      \n
      <meta charset=\"UTF-8\">
      \n<meta name=\"description\" content=\"AppleCare Training authored this course. If you use this course outside the AppleCare Training site, give credit to its author.\">\n<!-- If you are using an interaction to mark the page complete or if it is an AA page, change mark_complete to false -->\n
      <meta name=\"template_version\" content=\"01.05.2015\">
      \n
      <meta name=\"page\" content=\" \" mark_complete=\"false\">
      \n
      <link href=\"https://idesk.corp.apple.com/training/ce/_common/css/sgt.css\" media=\"screen, projection\" rel=\"stylesheet\" type=\"text/css\"/>
      \n<script>\n\tvar url = window.location.href;\n\tvar filename = \"\";\n\tvar is_local = url.substr(0,4);\n\tif(is_local==\"file\" || window.location.hostname === \"localhost\"){\n\t\t//Local Common Folder Location\n\t\tdocument.write(\'\\x3Cscript type=\"text/javascript\" src=\"http://localhost/_common/js/jquery.js\">\\x3C/script>\');\n\t\tdocument.write(\'\\x3Cscript type=\"text/javascript\" src=\"http://localhost/_common/js/ready.js\">\\x3C/script>\');\n\t}else{\n\t\tdocument.write(\'\\x3Cscript type=\"text/javascript\" src=\"/training/ce/_common/js/jquery.js\">\\x3C/script>\');\n\t\tdocument.write(\'\\x3Cscript type=\"text/javascript\" src=\"/training/ce/_common/js/ready.js\">\\x3C/script>\');\n\t}\n</script>\n\n
      <title>
         <target id=2>Key Terms and Concepts</target>
      </title>
      \n
   </head>
   \n\n
   <body class=\"aa\">
      \n\n\t\t\t<!-- BEGIN PAGE CONTENT -->\n\t
      <div id=\"maincontent\">
         \n
         <div id=\"learningcontentdiv\">
            \n
            <div id=\"morelearningcontentdiv\"></div>
            \n
         </div>
         \n\t\t\t
         <div id=\"content\">
            \n
            <div id=\"close_aa_term\">
               <target id=4>×</target>
            </div>
            \n
            <h2>
               <target id=6>Key Terms and Concepts</target>
            </h2>
            \n
            <p>
               <target id=8>You should already be familiar with all the terms in this module.</target>
               \t
            </p>
            \n\t
         </div>
         \n
      </div>
      \n\n<!-- END PAGE CONTENT -->\n
   </body>
   \n
</html>
"""

var javaScript = """
var richeditor = {};
var editor = document.body;

function getActiveDiv() {
    var sel = window.getSelection();
    var range = sel.getRangeAt(0);
    var node = document.createElement('span');
    range.insertNode(node);
    range = range.cloneRange();
    range.selectNodeContents(node);
    range.collapse(false);
    sel.removeAllRanges();
    sel.addRange(range);
    var activeDiv = node.parentNode;
    node.parentNode.removeChild(node);
    return activeDiv;
}

richeditor.insertText = function(text) {
    editor.innerHTML = text;
    window.webkit.messageHandlers.heightDidChange.postMessage(document.body.offsetHeight);
}

editor.addEventListener("input", function() {
var activeElement = getActiveDiv()
window.webkit.messageHandlers.textDidChange.postMessage("activeElement ID = "+ activeElement.id + " and TEXT = " + activeElement.innerHTML);
}, false)

document.addEventListener("selectionchange", function() {
    window.webkit.messageHandlers.heightDidChange.postMessage(document.body.offsetHeight);
}, false);

"""



override func viewDidLoad() {
    super.viewDidLoad()

    let config = WKWebViewConfiguration()
    config.userContentController = WKUserContentController()
    config.userContentController.add(self, name: "heightDidChange")
    config.userContentController.add(self, name: "textDidChange")
    config.userContentController.addUserScript(WKUserScript(source: javaScript, injectionTime: .atDocumentEnd, forMainFrameOnly: true))

    let webView = WKWebView(frame: CGRect(x: 0, y: 0, width: 400, height: 400), configuration: config)

    view.addSubview(webView)
    webView.loadHTMLString(htmlString, baseURL: nil)
    
    webView.navigationDelegate = self
    
  }


  func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
    print(message.name)
    let body = message.body
    print(body)
  }
    

}

extension ViewController : WKNavigationDelegate {
    
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!){
      webView.evaluateJavaScript("document.body.setAttribute('contentEditable','true')") { (anyObj: Any?, error: Error?) in
         if anyObj != nil{
             print("AnyObj in jave script : \(anyObj!)")
         }
         if error != nil{
             print("Error in Java script : \(error!)")
         }
        }
      }

}

【讨论】:

  • 这对我不起作用。但正如我在长问题中提到的,我的 html 字符串没有任何编辑器元素。我在问题中发布了我的 html 字符串。 (我不能在这里添加)
  • 更新代码以按照问题中提到的 html 工作。
  • 哇,谢谢你的回答。它运行良好。但是我编辑了htmlstring并添加了我的问题。在 html 字符串中,我添加了带有 ID 的标签 。每个字符串都有一些 id。我们能准确地知道用户正在编辑哪个 Target 元素吗?
  • 您可以为每个单独添加EventListener。
  • 您的意思是在 .js 文件中?但是在这里我们不知道目标ID。一切都应该以编程方式完成。
猜你喜欢
  • 2021-07-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多