V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
avenger
1D
V2EX  ›  Vue.js

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

  •  
  •   avenger ·
    bolechen · Apr 9, 2019 · 4874 views
    This topic created in 2578 days ago, the information mentioned may be changed or developed.

    需求是这样的

    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 基础功力还要加强,希望有这方面经验的大佬给一些指点,定重谢!

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

    ```
    onPageClick(event) {
    let { target } = event
    while (target && target.tagName !== 'A') target = target.parentNode;
    ```
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   2456 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 42ms · UTC 05:15 · PVG 13:15 · LAX 22:15 · JFK 01:15
    ♥ Do have faith in what you're doing.