需求是这样的
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="http://www.v2ex.com/bbb"> </a>
在上例中,我在事件开始输出 log,获取到的一直是 img 标签,而不是 a 标签,这也导致上面后续逻辑无法执行。
mounted () { window.addEventListener('click', event => { const { target } = event console.log(target)
看起来不是一个大问题,浪费了一晚上时间还没有解决。:( 我承认前端我接触太少,js 基础功力还要加强,希望有这方面经验的大佬给一些指点,定重谢!
![]() | 1 murmur 2019-04-09 23:29:44 +08:00 ![]() 大概意思懂了 只是我感觉难点在你的编辑器上 支持自定义链接的可视化编辑器很多 但是支持输入路由的编辑器还没见过 如果你能解决这一点 后面的处理就很随意了 这个例子的写法很明显是个冒泡捕获 你知道有一个 closest 你可以用这个函数找到触发事件最近的一个父级 a 标签 |
![]() | 2 0044200420 2019-04-09 23:29:57 +08:00 ![]() |
![]() | 4 avenger OP @0044200420 感谢,看了一下午冒泡了…… 还是没搞懂 :( |
5 randyo 2019-04-09 23:42:14 +08:00 via Android ![]() 判断一下 target 是不是 a 标签,不是的话判断他的 parentElement 是不是,不是的话重复上一步 |
![]() | 6 a62527776a 2019-04-10 00:05:07 +08:00 via Android 你用带渲染器的 vue 然后把 html 片段转换成你要的 vue template 再用 render 函数包裹起来执行一下就行了 |
![]() | 7 avenger OP 解决了,过来填个坑 ``` onPageClick(event) { let { target } = event while (target && target.tagName !== 'A') target = target.parentNode; ``` |