我有一个
<table-component />
组件,我希望我可以使用来自父级的数据和列对象创建行和列。
我有一种情况,我需要渲染一个html模板来创建一个可点击的链接,我让它想要在
Actions
列中显示链接。使用的Vue版本:^2.5.17.
这是来自
parent.vue
的代码:
<table-component :data="category" :column="column" class="bg-red-200 py-4 mt-8"/>
data() {
return {
modalMode: '',
isShowModalEdit: false,
category: [
{ id: 1, name: 'Jasa Pre-Order', color: '#eb4034' },
{ id: 2, name: 'Jualan', color: '#fcba03' },
{ id: 3, name: 'Jasa Design', color: '#9f34eb' },
],
}
}
// parent.vue
methods: {
toggleModalEdit(){
this.isShowModalEdit = !this.isShowModalEdit
this.modalMode = 'EDIT'
}
}
// parent.vue
computed: {
column() {
return [
{
dataField: 'name',
text: 'Name',
},
{
dataField: 'color',
text: 'Category Color',
formatter: (cell,row) => {
return `
<div style="background-color: ${cell};" class="rounded-full h-8 w-8 flex items-center justify-center mr-2"></div>
<div class="font-bold text-gray-500">${cell}</div>
`
},
classes: (cell, row, rowIndex, colIndex) => {
return 'flex';
}
},
{
dataField: 'actions',
text: 'Actions',
formatter: (cell,row) => {
return `
<a href="#" @click="${this.toggleModalEdit}" class="text-indigo-600 hover:text-indigo-900">Edit</a>
`
},
},
]
},
}
这是来自
component.vue
的示例代码:
// component.vue
<tbody class="bg-white divide-y divide-gray-200">
<tr v-for="(row, rowIndex) in data" :key="rowIndex">
<td v-for="(col, colIndex) in column" :key="col.dataField" :class=" col.classes ? col.classes(row[col.dataField],row,rowIndex,colIndex) : '' " v-html=" col.formatter ? col.formatter(row[col.dataField],row) : row[col.dataField] " class="px-6 py-4 whitespace-nowrap text-sm text-gray-500"></td>
<tr>
</tbody>
// component.vue
props: {
data: {
type: Array,
required: true
},
column: {
type: Array,
required: true
},
}
结果是这样的:
但是
Actions
列中的链接无法正常工作,我希望当单击此链接时将运行父级的方法,即toggleModalEdit
。这就是我检查链接时的样子:
我对Vue还是个新手,我不确定我做得最好或不好,我希望你们能提供帮助。
您的问题是,v-html 指令中的 HTML 根本没有被 Vue 的模板编译器处理。
因为编译器不会编译此 HTML,所以不会解释
@click
(只是简单地呈现而不触发任何操作)。
为此,您需要迭代所有列并初始化一个新组件,该组件直接在 HTML 中处理单元格内的内容(而不是在稍后渲染的某些字符串中)。
我想这已经足够了 - 如果您仍然需要解释字符串中的内容,您可以使用
Vue.compile
来解释内容。但要小心,因为它不安全,以防其中有一些恶意代码 - 但由于默认情况下指令根本没有任何清理,我想这就是 Vue.js 的工作方式。
感谢@SimplyComple0x78的回答,我标记了您的建议:
为此,您需要迭代所有列并初始化一个新组件,该组件直接在 HTML 中处理单元格内的内容(而不是在稍后渲染的某些字符串中)。
所以我尝试创建并初始化一个新组件,我称之为
element-generator
。 参考这里。这是代码:
// element-generator.vue
<script>
export default {
render: function (createElement) {
const generatedChildren = (child) => {
if(!child) return // when child of undefined
if(typeof child === 'string') return child // when children is String
return child.map((e,i,a)=>{
if(typeof child[i] == 'string'){
return child[i]
}else{
return createElement(
child[i].tag,
child[i].attributes,
generatedChildren(child[i].children) // javascript recursive
)
}
})
}
return createElement(
this.formatter.html.tag,
this.formatter.html.attributes,
generatedChildren(this.formatter.html.children)
)
},
props: {
formatter: {
type: Object,
required: true
},
},
}
</script>
并且我不再在
v-html
中使用 component.vue
,而是只在 <td>
内部进行检查并调用 element-generator
来处理单元格内的内容:
// component.vue
<tbody class="bg-white divide-y divide-gray-200">
<tr v-for="(row, rowIndex) in data" :key="rowIndex">
<td v-for="(col, colIndex) in column" :key="col.dataField"
:class=" col.classes ? col.classes(row[col.dataField],row,rowIndex,colIndex) : '' "
class="px-6 py-4 whitespace-nowrap text-sm text-gray-500"
>
<element-generator v-if="col.formatter" :formatter="col.formatter(row[col.dataField],row)"></element-generator>
<div v-else>{{row[col.dataField]}}</div>
</td>
</tr>
</tbody>
并且在
parent.vue
中,我将字符串替换为稍后将传递给element-generator
的对象,它看起来像这样:
// parent.vue
computed: {
column() {
return [
{
dataField: 'name',
text: 'Name',
},
{
dataField: 'color',
text: 'Category Color',
formatter: (cell,row) => {
return {
html: {
tag: 'div',
attributes: {
class: 'flex'
},
children:[
{
tag: 'div',
attributes: {
style: `background-color: ${cell};`,
class: 'rounded-full h-8 w-8 flex items-center justify-center mr-2',
},
},
{
tag: 'div',
attributes: {
class: 'font-bold text-gray-500',
},
children: cell
},
]
}
}
},
},
{
dataField: 'actions',
text: 'Actions',
formatter: (cell,row) => {
return {
html: {
tag: 'a',
attributes: {
class: 'text-indigo-600 hover:text-indigo-900',
on: {
click: this.toggleModalEdit
},
attrs: {
href: "#"
},
},
children: 'Edit'
},
}
},
},
]
},
},
然后当我在浏览器中检查它时,结果是这样的(这与之前的不同):
非常感谢大家。