Vue.js 3 Composition API ссылки из svg в router-link
У меня есть svg файл (карта оборудования), в котором есть ссылки на 3-д модели. Я хочу при клике по ссылке из svg файла открывать новый маршрут и подгружать свою 3-д модель, это работает с одним но - страница полностью перезагружается и дублируются все компоненты - то есть появляется 2 меню, 2 футера. Я считаю, что необходимо каким-то образом перехватить HTML ссылки из svg и переделать их в router-link. Единственное решение, которое смог найти https://dennisreimann.de/articles/delegating-html-links-to-vue-router.html , но у меня не получается его адаптировать и заставить работать.
В шаблоне подключаю svg через тег object
<div class="grid">
<div class="col-12 flex justify-content-center align-items-center princip-plan" @click="clickSVG">
<object type="image/svg+xml" :data="getModelBN800.link"> </object>
</div>
</div>
<script>
export default {
setup() {
onMounted(() => {
})
const modelStore = useModelStore()
const { getModelBN800 } = storeToRefs(modelStore)
const clickSVG = (event) => {
console.log(event)
let target = event
while (target && target.tagName !== 'A') target = target.parentNode
if (target && target.matches(".dynamic-content a:not([href*='://'])") && target.href) {
if (button !== undefined && button !== 0) return
if (target && target.getAttribute) {
const linkTarget = target.getAttribute('target')
if (/\b_blank\b/i.test(linkTarget)) return
}
const url = new URL(target.href)
const to = url.pathname
if (window.location.pathname !== to && event.preventDefault) {
event.preventDefault()
this.$router.push(to)
}
}
}
return { getModelBN800, clickSVG }
}
}
</script>
Сейчас функция clickSVG ни как не реагирует. Если я добавлю стиль pointer-events:none; к object тогда клик срабатывает, но target.tagName не находит ссылок, а только div на котором повешен клик. Если повесить клик на object, ни каких действий не происходит. Какие есть варианты решения моей задачи?
На основе решения Александра Сычева (ниже в комментариях). Я попытался адаптировать решение для себя и получаю ошибку Cannot read properties of null (reading 'contentDocument') .
Я создал функцию clickSVG2 и добавил ее в onMounted:
onMounted(() => {
clickSVG2()
})
const clickSVG2 = () => {
window.addEventListener("load", () => {
// const a = ref(null)
// console.log(a.value)
const a = document.getElementById("Plan").contentDocument
const b = a.getElementById("svg4504")
const c = b.querySelectorAll("a")
c.forEach(i => {
i.addEventListener('click', (e) => {
e.preventDefault()
console.log(i)
})
})
});
}
Я добавил id="Plan" в object, а внутри моего svg файла id svg4504. Также я пытался повесить ссылку ref на object, но также безрезультатно. Также я должен сообщить, что не могу разместить svg inline, ибо файл является сложным и в нем 40К строк
Ответы (2 шт):
Если правильно понял, то главная проблема, получить url ссылки из svg --- написал на js, под vue адаптируете сами --- ( как вариант на mounted() установить )
Пример svg:
<?xml version="1.0" ?>
<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.0//EN' 'http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd'>
<svg id="Layer_1" style="enable-background:new 0 0 200 200;" version="1.0" viewBox="0 0 200 200" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<style type="text/css">
.st0{fill:none;stroke:#000000;stroke-width:7;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:10;}
</style>
<a id="ancor0" href="/ancor0">
<rect height="17.3" width="7" x="100.7" y="116.5"/>
</a>
<a id="ancor1" href="/ancor1">
<rect height="17.3" width="7" x="117.7" y="116.5"/>
</a>
<a id="ancor2" href="/ancor2">
<rect height="17.3" width="7" x="133.7" y="116.5"/>
</a>
<a id="ancor3" href="/ancor3">
<rect height="17.3" fill="red" width="7" x="148.7" y="116.5"/>
</a>
</svg>
Поиск на js:
window.addEventListener("load", () => {
const a = document.getElementById("svgObject").contentDocument
const b = a.getElementById("Layer_1")
const c = b.querySelectorAll("a")
c.forEach(i => {
i.addEventListener('click', (e) => {
e.preventDefault()
console.log(i)
})
})
});
<div>
<object id="svgObject" data="1489437033-house10_81899.svg" type="image/svg+xml" width="100%" height="100%">
Your browser doesn't support SVG
</object>
</div>
обязательно нужно дождаться загрузки всех файлов
window.addEventListener("load", () => {...
Так как svg не успевал загрузиться, то сделал через SetTimeout и все прекрасно работает. Нахожу все ссылки в svg, из них достаю id (заранее известно, что id будет в конце ссылки) и вешаю клик обработчик, который отменяет действие по умолчанию и пушит на нужный маршрут. Функцию ниже надо вешать в блок setup - onMounted. Благодарю Александра Сычева за помощь в решении.
const linksReplacement = () => {
setTimeout(function(){
const object = document.getElementById("Plan").contentDocument
const svg = object.getElementById("svg4504")
const links = svg.querySelectorAll("a")
console.log(links);
links.forEach(link => {
link.addEventListener('click', (e) => {
e.preventDefault()
let url = link.href.baseVal
//let id = url.split('/').splice(-1, 1)
let id = url.split('/').pop()
console.log(id)
router.push({
name: 'info.models.show',
params: {
id: id,
},
})
})
})
}, 1000)
}