Dcat Admin 自定义页面 script 标签内的 HTML 闭合标签(例如 </li> )被自动删除的解决办法
问题描述
今天我尝试将 Vue
引入 Dcat Admin
的自定义页面中,因为自定义页面中使用 JQuery
操作 DOM 很麻烦。本来一切都很顺利,但在我尝试将 Vue 组件引入页面的时候,看到浏览器控制台有一行警告信息,提示 Vue 组件的 template 中的 HTML 元素缺失闭合标签,警告信息如下:
我找到了 Dcat Admin 为该自定义页面生成的代码,如下:
template 中的 HTML 元素确实没有闭合标签,但是我的代码是写了闭合标签的:
// custom-color.blade.php:
<div id="custom-color-page">
...
</div>
<script init="#custom-color-page">
......
window.vueApp = Vue.createApp(customColorPage);
window.vueApp.component('todo-item',{
props: ['todo'],
template: '<li> @{{ todo.text }} </li>',
data(){
return {
name: 'Song'
}
}
})
window.vueApp.mount('#custom-color-page');
</script>
我百思不得其解,起初以为是 Vue 与 Dcat Admin 有冲突,于是我就尝试用 JQuery 试一下:
// custom-color.blade.php:
<div id="custom-color-page">
...
</div>
<script init="#custom-color-page">
console.log(jQuery('<li>item</li>'));
</script>
Dcat Admin 生成的该自定义页面对应的代码如下:
也是同样的问题,HTML 元素的闭合标签丢失了。
于是,我使用 dd()
函数一步一步调试,最后发现问题出在以下代码里:
/**
* @param string $html
* @return DOMDocument
*
* @throws \Throwable
*/
protected static function getDOMDocument(string $html)
{
$dom = new DOMDocument();
libxml_use_internal_errors(true);
$dom->loadHTML('<?xml encoding="utf-8" ?>'.$html);
// 执行完 $dom->loadHTML 后,script 标签内 HTML 元素的闭合标签完全丢掉了
libxml_use_internal_errors(false);
return $dom;
}
也就是说, DOMDocument 实例在执行完 loadHtml 方法后将 script 标签内的 HTML 元素的闭合标签移除掉了。至于原因我也没有搞清楚。
解决办法
在闭合标签的斜杠(/
)前加个反斜杠(\
),更改后的代码如下:
// custom-color.blade.php:
<div id="custom-color-page">
...
</div>
<script init="#custom-color-page">
......
window.vueApp = Vue.createApp(customColorPage);
window.vueApp.component('todo-item',{
props: ['todo'],
// 闭合标签处加了反斜杠
template: '<li> @{{ todo.text }} <\/li>',
data(){
return {
name: 'Song'
}
}
})
window.vueApp.mount('#custom-color-page');
现在,控制台没有标签闭合的警告了,但是目前我不清楚原因在哪里,加反斜杠(\
)的解决办法也是我瞎试出来的,而且我觉得解决办法并不完美。
更好的解决办法是将 Vue 组件单独定义到一个 JavaScript 文件中,然后用admin_js
方法引入。
test-component.js:
function todoItemComponent(){
window.vueApp.component('todo-item',{
props: ['todo'],
template: '<li> {{ todo.text }} </li>',
data(){
return {
name: 'Song'
}
}
})
}
custom-color.blade.php:
<div id="custom-color-page">
<ol>
<todo-item v-for="todoItem in groceryList" v-bind:key="todoItem.id" v-bind:todo="todoItem"></todo-item>
</ol>
</div>
{!! admin_js(['/js/components/test-component.js']) !!}
<script init="#custom-color-page">
const customColorPage = {
data(){
return {
counter: 0,
groceryList: [
{id: 1, text: 'apple'},
{id: 2, text: 'xiaomi'},
{id:3, text: 'Cheese'}
]
}
},
methods: {
addCounter(){
this.counter++;
}
}
}
window.vueApp = Vue.createApp(customColorPage);
todoItemComponent();
window.vueApp.mount('#custom-color-page');
</script>
这个坑我终于踩到了 :sob: