@click 在使用 v-html 渲染时不起作用

问题描述 投票:0回答:2

我有一个

<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还是个新手,我不确定我做得最好或不好,我希望你们能提供帮助。

javascript vue.js
2个回答
2
投票

您的问题是,v-html 指令中的 HTML 根本没有被 Vue 的模板编译器处理

因为编译器不会编译此 HTML,所以不会解释

@click
(只是简单地呈现而不触发任何操作)。

为此,您需要迭代所有列并初始化一个新组件,该组件直接在 HTML 中处理单元格内的内容(而不是在稍后渲染的某些字符串中)。

我想这已经足够了 - 如果您仍然需要解释字符串中的内容,您可以使用

Vue.compile
来解释内容。但要小心,因为它不安全,以防其中有一些恶意代码 - 但由于默认情况下指令根本没有任何清理,我想这就是 Vue.js 的工作方式。


0
投票

感谢@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'
                        },
                    }
                },
            },
        ]
    },
},

然后当我在浏览器中检查它时,结果是这样的(这与之前的不同):

最后,单击 Edit 时我想要显示的内容现在显示:


非常感谢大家。

© www.soinside.com 2019 - 2024. All rights reserved.