ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

把 CodeMirror 中链接变为可点击(Clickable Link)

2021-04-08 17:33:18  阅读:325  来源: 互联网

标签:node const cm Link result Clickable line CodeMirror 链接


问题

很多编辑器,比如 VSCode 都可以自动检测文本中的链接,然后点击链接就可以打开网页。

但是 CodeMirror(一个基于 Web 的编辑器,CodePen 用的就是这个)没有自带这个功能,所以需要手动添加。

添加后的效果:

样例

解决

方法 1(推荐)

利用 cm.eachLine 对每一行进行遍历,用正则表达式判断其中的链接,并用 cm.markText 给链接文本添加 className,

之后再监听点击事件,判断点击的元素的 className,根据按键类别打开链接。

// editor 就是 CodeMirror 的实例,也就是上面说的 cm

const urlRegex = /(https?):\/\/[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]/g

editor.eachLine(line => {
  const result = line.text.match(urlRegex)?.[0]
  if (result) {
    const posLine = editor.lineInfo(line).line   // 链接的行号
    const posStart = line.text.indexOf(result)   // 链接的起始字符位置
    const posEnd = posStart + result.length      // 结束字符位置

    editor.markText(
      { line: posLine, ch: posStart },
      { line: posLine, ch: posEnd },
      {
        className: 'cm-clickable-link',  // 也可以直接替换文本,https://codemirror.net/doc/manual.html#markText
      }
    )
  }
})

editor.on('mousedown', (_cm, event) => {
  // 1 = 鼠标左键,2 = 鼠标右键,4 = 鼠标中键
  if (event.buttons === 1 || event.buttons === 4) {
    const element = event.target as Element
    if (element.classList.contains('cm-clickable-link')) {
      // 打开链接 ...
    }
  }
})

方法 2

cm.renderLine 中直接添加包含链接的元素的 className,这种方法的缺点是包含链接的元素中可能不止含有链接,比如还有引号之类的。

下面是我参考的一个开源项目 tulios/json-viewer 的效果,后面的代码也是我根据他改编的。

方法2

editor.on('renderLine', (cm, line, element) => {
  // 选择一行中所有的 `.cm-string`,这里对应的是 JSON 中的 `值`,可以根据自己的需求改
  const nodes = element.querySelectorAll('.cm-string')
  if (nodes && nodes.length > 0) {
    // 对于每一个 `.cm-string` 执行 ...
    nodes.forEach(node => {
      if (node) {
        const result = node.textContent?.match(urlRegex)?.[0]
        if (result) {
          node.classList.add('cm-clickable-link')
          node.setAttribute('url', result)
        }
      }
    })
  }
})

// 后面和 方法 1 中的监听 mousedown 相同

方法 3

针对 方法 2 中的缺点,还有一种解决方法就是直接替换 node 为 HTML,

但这种方法也有缺点,就是修改后的链接无法被选中,而且在某些时候会消失,性能也不好。

editor.on('renderLine', (cm, line, element) => {
  const nodes = element.querySelectorAll('span')
  if (nodes && nodes.length > 0) {
    nodes.forEach(node => {
      if (node) {
        const result = node.textContent?.match(urlRegex)?.[0]
        if (result) {
          // node.classList.add('cm-clickable-link')
          // node.setAttribute('url', result)
          // 替换成:
          node.innerHTML = node.innerHTML.replace(
            result,
            `<span data-url="${result}" class="cm-string cm-clickable-link">${result}</span>`
          )
        }
      }
    })
  }
})

标签:node,const,cm,Link,result,Clickable,line,CodeMirror,链接
来源: https://www.cnblogs.com/liangfengning/p/14633414.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有