【问题标题】:Use Vue component data in JavaScript在 JavaScript 中使用 Vue 组件数据
【发布时间】:2021-12-08 11:51:58
【问题描述】:

我们应该如何从应用程序外部访问 Vue 组件的数据?例如,我们如何在常规 JavaScript onClick 事件中获取数据,该事件由 Vue 应用程序外部 DOM 中的按钮触发。

在下面的设置中,我有一个隐藏字段,我会在 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 核心剃须刀页面的表单时将来自 Vue 应用程序的数据与其他非 Vue 数据一起发送。 Vue 应用程序只是 razor 视图的特定部分,因此不是 SPA。

提前致谢!

【问题讨论】:

    标签: javascript vue.js asp.net-core


    【解决方案1】:

    这是一个相当复杂的解决方案 - 但至少它相当灵活。

    1. 创建一个Vue.observable 存储:这不是别的,而是一个反应对象
    2. Vue 实例中创建要用于更新observable 的方法
    3. 在商店中添加一个watcher:这是一个标准的Vue 对象和一个$watch 设置
    4. 如果store 更改(watcher 实例)设置回调:此回调是您可以与“外部世界”联系的地方

    片段:

    const countervalueSpan = document.getElementById('countervalue')
    
    // creating a Vue.observable - 
    // reactive object
    const store = Vue.observable({
      counter: 0
    })
    
    // setting up a watcher function
    // using the Vue object
    function watch(obj, expOrFn, callback, options) {
      let instance = null
    
      if ('__watcherInstance__' in obj) {
        instance = obj.__watcherInstance__
      } else {
        instance = obj.__watcherInstance__ = new Vue({
          data: obj
        })
      }
    
      return instance.$watch(expOrFn, callback, options)
    }
    
    // creating a watcher that reacts
    // if the given store item changes
    const subscriber = watch(
      store,
      'counter',
      (counter) => {
        let html = `<strong>${counter}</strong>`
        countervalueSpan.innerHTML = html
      }
    )
    
    new Vue({
      el: "#app",
      methods: {
        increment() {
          store.counter++
        }
      },
      template: `
        <div>
          <button
            @click="increment"
          >
            INCREMENT
          </button>
        </div>
      `
    })
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
    <div id="outside">
      Counter outside: <span id="countervalue"></span>
    </div>
    <div id="app"></div>

    您始终可以轻松地从外部访问store 对象(例如store.counter)并且您始终可以获取对象的当前状态。需要观察者自动对更改做出反应。

    【讨论】:

      【解决方案2】:

      我建议不要这样做并将所有内容包装在 Vue 中或直接使用 JQuery,具体取决于您网站的构建方式。拥有多个前端框架通常是个坏主意,并且会引入不必要的复杂性。

      但是,如果您确实需要使用纯 javascript 访问 Vue 的数据,您可以使用以下内容:

      const element = document.getElementById('#element-id');
      element._instance.data // or element._instance.props, etc...
      

      对于可用的属性,您可以查看检查器(参见随附的屏幕截图)。 Inspector screenshot

      【讨论】:

      • 事情是这样的。在我们当前的框架中,我们可以使用 .net core MVC 快速生成基本的 CRUD 页面。有时我们需要为这样的页面添加动态行为。例如,需要管理“证书”列表的“车辆”页面(添加/删除/编辑)。这是我试图用 Vue 做的证书列表。替代方案确实是使用 JQuery 代码创建部分剃刀视图?
      • 如果你只在这部分使用 Vue,而在整个网站上使用 JQuery,我将只使用 JQuery 重建证书列表,这样使用隐藏输入可能也有意义。
      猜你喜欢
      • 2017-12-01
      • 2021-02-12
      • 2017-04-29
      • 1970-01-01
      • 2023-04-03
      • 2016-03-26
      • 2018-07-03
      • 2020-04-14
      • 1970-01-01
      相关资源
      最近更新 更多