You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Vue应用外部的JavaScript中访问Vue组件数据

问题:如何从Vue应用外部访问组件数据实现Razor表单同步提交

我们应该如何从Vue应用外部访问Vue组件的数据?例如,当触发位于Vue应用外部DOM中的按钮的普通JavaScript onClick事件时,我们该如何获取对应的数据?

在我目前的实现方案中,我设置了一个隐藏字段,每次Vue应用内执行操作时都会更新该字段的值,这样JS点击事件就能获取到所需的数据,但我认为肯定有更优的实现方式。

我当前的配置如下:
VehicleCertificates.js

import { createApp, Vue } from 'vue'
import VehicleCertificates from './VehicleCertificates.vue';

const mountEl = document.querySelector("#certificates");
const app = createApp(VehicleCertificates, { ...mountEl.dataset })
const vm = app.mount("#certificates");

VehicleCertificates.vue

<template>
    <div style="background-color: red;">
        <h3>Certificates</h3>
        <div>
            <table class="table table-striped table-hover table-condensed2" style="clear: both;">
                <thead>
                    <tr>
                        <th><b>Type</b></th>
                        <th><b>Valid From</b></th>
                        <th><b>Valid Till</b></th>
                        <th style="text-align: right;">
                            <a href="#" @click='addCertificate'>
                                <i class="fa fa-plus-square"></i> Add
                            </a>
                        </th>
                    </tr>
                </thead>
                <tbody>
                    <tr v-for="(certificate, index) in certificates" :key="index">
                        <td>{{ certificate.CertificateTypeDescription }}</td>
                        <td>
                            {{ certificate.ValidFrom }}
                        </td>
                        <td>
                            {{ certificate.ValidTo }}
                        </td>
                        <td>
                            <a href='#' @click="removeCertificate(index)" title="Delete" style="float: right;" class="btn btn-default">
                                <i class="fa fa-trash"></i>
                            </a>
                        </td>
                    </tr>
                    <tr v-show="certificates.length == 0">
                        <td colspan="4">
                            No certificates added
                        </td>
                    </tr>
                </tbody>
            </table>
        </div>
    </div>
</template>

<script>
    import axios from 'axios';
    import { onMounted, ref } from "vue";

    export default {
        props: {
            vehicleId: String
        },
        data() {
            return {
                count: 0,
                certificates: ref([]),
                types: []
            }
        },
        created() {
            onMounted(async () => {
                let result = await axios.get("/api/v1.0/vehicle/GetCertificates", { params: { vehicleId: this.vehicleId } });
                this.certificates.splice(0, 0, ...result.data);
                this.certificatesUpdated();
            });
        },
        methods: {
            removeCertificate(index) {
                this.certificates.splice(index, 1);
                this.certificatesUpdated();
            },
            addCertificate() {
                this.certificates.push({ CertificateTypeDescription: 'ADR', ValidFrom: 1, ValidTo: 2 });
                this.certificatesUpdated();
            },
            certificatesUpdated() {
                $("#VehicleCertificatesJson").val(JSON.stringify(this.certificates));
            }
        }
    }
</script>

我的最终需求是:在提交ASP.NET Core Razor页面的表单时,能够将Vue应用中的数据和其他非Vue数据一同提交。该Vue应用仅作为Razor视图的特定部分存在,并非单页应用(SPA)。


解答

结合你非SPA嵌入Razor页面的场景,有两种成熟的优化方案可选:

方案1:全局挂载组件实例(最简单,适配所有外部调用场景)

你当前代码中已经获取到了挂载后的组件实例vm,只需要将其挂载到全局window对象上,外部JS就可以直接访问组件内的所有数据和方法:

// 修改VehicleCertificates.js
import { createApp } from 'vue'
import VehicleCertificates from './VehicleCertificates.vue';

const mountEl = document.querySelector("#certificates");
const app = createApp(VehicleCertificates, { ...mountEl.dataset })
const vm = app.mount("#certificates");
// 新增:挂载到全局window
window.vehicleCertificatesVM = vm;

之后不管是外部按钮点击事件还是表单提交逻辑,都可以直接获取数据:

// 外部JS直接访问组件数据
const certificates = window.vehicleCertificatesVM.certificates;
// 提交前一次性同步到隐藏域即可,无需每次修改组件数据都更新
document.querySelector("#VehicleCertificatesJson").value = JSON.stringify(certificates);

附带优化点

你当前代码中存在两个不规范写法,可一并修改:

  1. 选项式API的data返回值本身就是响应式的,不需要用ref包裹,把certificates: ref([])改为certificates: []即可
  2. onMounted是组合式API的钩子,选项式API直接使用mounted配置项即可,不需要单独导入,也不要写在created钩子内。

方案2:组件内部监听表单提交事件(无全局污染,和原有逻辑完全兼容)

如果不想污染全局作用域,可以在组件内部监听Razor表单的提交事件,提交前自动同步数据到隐藏域,外部完全不需要感知Vue的存在:

// 修改VehicleCertificates.vue的script部分
<script>
import axios from 'axios';

export default {
    props: {
        vehicleId: String
    },
    data() {
        return {
            count: 0,
            certificates: [],
            types: []
        }
    },
    // 替换原有的created配置
    async mounted() {
        const result = await axios.get("/api/v1.0/vehicle/GetCertificates", { params: { vehicleId: this.vehicleId } });
        this.certificates.splice(0, 0, ...result.data);
        // 监听表单提交事件,替换为你实际的表单ID
        document.querySelector("#yourFormId").addEventListener("submit", this.syncDataToHiddenField);
    },
    beforeUnmount() {
        // 组件销毁前移除监听,避免内存泄漏
        document.querySelector("#yourFormId")?.removeEventListener("submit", this.syncDataToHiddenField);
    },
    methods: {
        syncDataToHiddenField() {
            document.querySelector("#VehicleCertificatesJson").value = JSON.stringify(this.certificates);
        },
        removeCertificate(index) {
            this.certificates.splice(index, 1);
        },
        addCertificate() {
            this.certificates.push({ CertificateTypeDescription: 'ADR', ValidFrom: 1, ValidTo: 2 });
        }
        // 原有的certificatesUpdated方法可以直接删除,无需每次修改都同步
    }
}
</script>

这种方案和你原有的Razor表单提交逻辑完全兼容,后端模型绑定不需要做任何修改。


内容的提问来源于stack exchange,提问作者Yan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 07:27:02