繁体   English   中英

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

[英]@click doesn't work when rendering it using v-html

我有一个组件,我希望我可以使用父级的数据和列 object 创建行和列。

有一种情况,我需要渲染一个 html 模板来创建一个可点击的链接,我让它想在Actions列中显示该链接。 vue 版本:^2.5.17



下面是来自parent.vue的代码:
// 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>
                            `
                        },
                    },
                ]
            },
}
 // parent.vue 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' }, ], } }
// 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
            },
}
这是来自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列中的链接无法正常工作,我希望单击此链接时将运行 perent 的方法,即toggleModalEdit 这就是我检查链接时的样子:

在此处输入图像描述


我还是vue的新手,我不确定我做得最好还是没有,希望你们能提供帮助。

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

因为编译器不编译这个@click ,@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>

而且我不再在component.vue中使用v-html ,而是在<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中,我用 Object 替换了字符串,稍后将传递给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'
                        },
                    }
                },
            },
        ]
    },
},

然后当我在浏览器中检查它时,结果是这样的(这与上一个不同): 在此处输入图像描述

最后,现在显示了单击编辑时要显示的内容: 在此处输入图像描述


非常感谢大家。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM