80 lines
1.5 KiB
Vue
80 lines
1.5 KiB
Vue
<script setup>
|
|
const props = defineProps({
|
|
code: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
location: {
|
|
type: String,
|
|
default: ''
|
|
}
|
|
})
|
|
|
|
const slotRef = ref(null)
|
|
const mounted = ref(false)
|
|
const normalizedCode = computed(() => String(props.code || '').trim())
|
|
|
|
/**
|
|
* v-html로 삽입된 광고 스크립트를 브라우저에서 실행 가능한 노드로 교체한다.
|
|
* @returns {void}
|
|
*/
|
|
const executeAdScripts = () => {
|
|
if (!import.meta.client || !(slotRef.value instanceof HTMLElement)) {
|
|
return
|
|
}
|
|
|
|
const scripts = Array.from(slotRef.value.querySelectorAll('script'))
|
|
|
|
scripts.forEach((script) => {
|
|
const nextScript = document.createElement('script')
|
|
|
|
Array.from(script.attributes).forEach((attribute) => {
|
|
nextScript.setAttribute(attribute.name, attribute.value)
|
|
})
|
|
|
|
nextScript.text = script.text || script.textContent || ''
|
|
script.replaceWith(nextScript)
|
|
})
|
|
}
|
|
|
|
watch(normalizedCode, async () => {
|
|
await nextTick()
|
|
executeAdScripts()
|
|
})
|
|
|
|
onMounted(async () => {
|
|
mounted.value = true
|
|
await nextTick()
|
|
executeAdScripts()
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<div
|
|
v-if="mounted && normalizedCode"
|
|
ref="slotRef"
|
|
class="site-ad-slot"
|
|
role="complementary"
|
|
aria-label="광고"
|
|
:data-ad-location="location || undefined"
|
|
v-html="normalizedCode"
|
|
/>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.site-ad-slot {
|
|
width: 100%;
|
|
max-width: 100%;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.site-ad-slot :deep(ins.adsbygoogle) {
|
|
display: block;
|
|
max-width: 100%;
|
|
}
|
|
|
|
.site-ad-slot :deep(iframe) {
|
|
max-width: 100%;
|
|
}
|
|
</style>
|