# Vue3 v-html / Nuxt3 v-html ## Vue v-html 最近在接公司前後台資訊,其中在編輯商品時,是使用[CKEditor5](https://ckeditor.com/ckeditor-5/)這個套件進行編輯的,存在資料庫的內容就會是HTML標籤語言,如下: ``` HTML '<p><a href="/">商品描述商品描述</a></p>' ``` 在做Vue前端時,就不能使用`{{}}`大括號在模板語言中直接使用,因為字串中包含實體字符,至於關於實體字符可以參考[這篇](https://ithelp.ithome.com.tw/articles/10202232#v-html)。 那這邊馬上來實際運用一下: 父元件會傳productDetail這個props,定義好props及預設值後,我用一個computed先進行處理,CKEditor5在嵌入iframe影片時,要做一些處理,因為CKEditor5轉換出來的HTML在前端顯示不出來。 那`data_processEmbedTag`就是處理後的字串。 ```Typescript <script setup lang="ts"> interface IProps { productDetail?: string; } const props = withDefaults(defineProps<IProps>(), { productDetail: '', }); console.log(props.productDetail); // translate ck editor5 youtube iframe const data_processEmbedTag = computed( () => props.productDetail?.replaceAll('oembed', 'iframe').replaceAll('url', 'src').replaceAll('watch?v=', 'embed/') ?? '' ); </script> ``` 接下來就可以使用`v-html`綁進去vue 模板語言裡面的DOM元素了: ```HTML <template> <div class="flex flex-col"> <div v-html="data_processEmbedTag"></div> </div> </template> ``` 這是`data_processEmbedTag`的內容: ![](https://i.imgur.com/sF8J7jV.png) 這是`v-html`呈現的內容: ![](https://i.imgur.com/XokOm2c.png) 綁進去後你會發現,v-html裡面所有的元素都吃不到css,只有存進去資料庫的inline style會作用而已。所以這時候你就要使用vue的css的深度選擇器。 ## Vue的css的深度選擇器 先說說為什麼要使用到深度選擇器: Vue在選染模板語言時,都會賦予元素一個Hash屬性,所以在瀏覽器的開發人員工具(F12)中常常會看到`data-v-hash`的元素,但是使用`v-html`渲染出來的不會有這樣的Hash屬性。 再來因為Vue在寫css樣式,可以使用關鍵字`<style scoped>`,可是使你在子物件裡定義的樣式,不會向外汙染全域的樣式,所以在正常情況會使用`scoped`關鍵字。但這時你寫了一個style,就會只渲染在同一個Hash的原件,沒有Hash的是吃不到你設定的樣式的,例如:`v-html`產生出來的DOM元素。 元件在開發人員工具呈現的樣子: ```HTML <div data-v-bc5f04ec="">...</div> ``` 那冠有`scoped`的樣式就會這樣呈現: ```css table[data-v-bc5f04ec], th[data-v-bc5f04ec], td[data-v-bc5f04ec] { @apply border-1 border-border-color; } ``` 所以這樣是沒有辦法發揮樣式的作用的。所以就套上深度選擇器吧: ```css // deep selector change v-html style :deep(*) { @apply text-sm tracking-wide; table, th, td { @apply border-1 border-border-color; } } :deep(figure.media) { iframe { @apply w-full; height: var(--global-iframe-height); } } :deep(iframe) { @apply w-full; height: var(--global-iframe-height); } ``` 套用上深度選擇器後,就可以正常呈現了: ![](https://i.imgur.com/eB25rVz.png) ### 深度選擇器其他寫法 深度選擇器其實還有其他寫法: 寫法一:`::v-deep` ``` ::v-deep table, ::v-deep th, ::v-deep td { @apply border-1 border-border-color; } ``` 這種寫法在Vue3會被警告: ```bash [@vue/compiler-sfc] ::v-deep usage as a combinator has been deprecated. Use :deep(<inner-selector>) instead. ``` 寫法二:`>>>` ``` >>> table, >>> th, >>> td { @apply border-1 border-border-color; } ``` 寫法三:`/deep/` ``` /deep/ table, /deep/ th, /deep/ td { @apply border-1 border-border-color; } ``` 寫法二、三寫法在Vue3也會被警告: ```bash [@vue/compiler-sfc] the >>> and /deep/ combinators have been deprecated. Use :deep() instead. ``` #### 結論 所以是Vue3的狀態下,還是使用`:deep(<inner-selector>)`的寫法吧!