请教一个 Vue.js 动态加载外部 html 的事件处理问题

2019-04-09 23:22:27 +08:00
 avenger

需求是这样的

Vue 单页 app,app 首页用户需要自定义,内容是后台用户编辑的,前端通过 api 来获取用户后台编辑的内容,api 返回 html 格式。

现在需要在前端输出 html 的时候,处理 html 中的所有链接,捕获默认的点击事件,转换成 Vue-route 的本地事件,跳到对应的路由页面。

网上已经找到一位老哥的代码了( https://dennisreimann.de/articles/delegating-html-links-to-vue-router.html ),思路如下:

    <div
      class="imgs content"
      v-html="app.home"
    />
mounted () {
  window.addEventListener('click', event => {
    const { target } = event
    // handle only links that do not reference external resources
    if (target && target.matches("a:not([href*='://'])") && target.href) {
      // some sanity checks taken from vue-router:
      // https://github.com/vuejs/vue-router/blob/dev/src/components/link.js#L106
      const { altKey, ctrlKey, metaKey, shiftKey, button, defaultPrevented } = event
      // don't handle with control keys
      if (metaKey || altKey || ctrlKey || shiftKey) return
      // don't handle when preventDefault called
      if (defaultPrevented) return
      // don't handle right clicks
      if (button !== undefined && button !== 0) return
      // don't handle if `target="_blank"`
      if (target && target.getAttribute) {
        const linkTarget = target.getAttribute('target')
        if (/\b_blank\b/i.test(linkTarget)) return
      }
      // don't handle same page links/anchors
      const url = new URL(target.href)
      const to = url.pathname
      if (window.location.pathname !== to && event.preventDefault) {
        event.preventDefault()
        this.$router.push(to)
      }
    }
  })
}

本地调试的时候发现一个问题,api 返回的 html 是类似这样的

<a href="/xxx">
  <img src="/bbb">
</a>

在上例中,我在事件开始输出 log,获取到的一直是 img 标签,而不是 a 标签,这也导致上面后续逻辑无法执行。

mounted () {
  window.addEventListener('click', event => {
    const { target } = event
    console.log(target)

看起来不是一个大问题,浪费了一晚上时间还没有解决。:( 我承认前端我接触太少,js 基础功力还要加强,希望有这方面经验的大佬给一些指点,定重谢!

4213 次点击
所在节点    Vue.js
7 条回复
murmur
2019-04-09 23:29:44 +08:00
大概意思懂了 只是我感觉难点在你的编辑器上 支持自定义链接的可视化编辑器很多 但是支持输入路由的编辑器还没见过
如果你能解决这一点 后面的处理就很随意了
这个例子的写法很明显是个冒泡捕获 你知道有一个 closest 你可以用这个函数找到触发事件最近的一个父级 a 标签
0044200420
2019-04-09 23:29:57 +08:00
avenger
2019-04-09 23:40:40 +08:00
@murmur 感谢,初衷是后台直接输入 http 链接,前端再根据链接转换成 vue 用的路由
avenger
2019-04-09 23:41:07 +08:00
@0044200420 感谢,看了一下午冒泡了…… 还是没搞懂 :(
randyo
2019-04-09 23:42:14 +08:00
判断一下 target 是不是 a 标签,不是的话判断他的 parentElement 是不是,不是的话重复上一步
a62527776a
2019-04-10 00:05:07 +08:00
你用带渲染器的 vue 然后把 html 片段转换成你要的 vue template 再用 render 函数包裹起来执行一下就行了
avenger
2019-04-13 11:12:49 +08:00
解决了,过来填个坑

```
onPageClick(event) {
let { target } = event
while (target && target.tagName !== 'A') target = target.parentNode;
```

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/553534

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX