需求是这样的
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 基础功力还要加强,希望有这方面经验的大佬给一些指点,定重谢!
1
murmur 2019-04-09 23:29:44 +08:00 1
大概意思懂了 只是我感觉难点在你的编辑器上 支持自定义链接的可视化编辑器很多 但是支持输入路由的编辑器还没见过
如果你能解决这一点 后面的处理就很随意了 这个例子的写法很明显是个冒泡捕获 你知道有一个 closest 你可以用这个函数找到触发事件最近的一个父级 a 标签 |
2
0044200420 2019-04-09 23:29:57 +08:00 1
|
4
avenger OP @0044200420 感谢,看了一下午冒泡了…… 还是没搞懂 :(
|
5
randyo 2019-04-09 23:42:14 +08:00 via Android 1
判断一下 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; ``` |