首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从Vue.js外部更改Vue.js数据

从Vue.js外部更改Vue.js数据
EN

Stack Overflow用户
提问于 2022-03-13 11:45:41
回答 2查看 433关注 0票数 1

我有一个简单的购物车演示。

它有3个Vue应用程序,一个作为共享上下文的全局对象,以及一个在Vanilla JS中的按钮。

如果您通过Vue应用程序将产品添加到购物车中,那么一切都正常。

但如果你用香草JS按钮,什么都不能用。

基本上,我希望在Vue应用程序之外更改全局对象,然后以某种方式强制视图捕获更改。

我怎么能这么做?

我之所以这么做是因为我在一个新的应用程序中逐步使用Vue.js。是is jQuery的一部分,也是Vue的一部分。它们都将全局对象作为共享对象进行操作。

这是我的JS代码:

代码语言:javascript
复制
let cart = { orderLines: [], itemsCount: 0 }

let addViaJs = document.querySelector('#addViaJs');
addViaJs.addEventListener('click', () => {
    cart.orderLines[0].quantity += 1; // this line does not cause update in UI
});

let miniCart = {
    data() {
        return {
            cart,
        }
    },
    computed: {
        itemsCount() {
            let itemsCount = 0;
            for (let i = 0; i < this.cart.orderLines.length; i++) {
                itemsCount += this.cart.orderLines[i].quantity || 0;
            }
            return itemsCount;
        }
    },
};
Vue.createApp(miniCart).mount('#miniCart');

let bigCart = {
    data() {
        return {
            cart,
        }
    },
    computed: {
        itemsCount() {
            let itemsCount = 0;
            for (let i = 0; i < this.cart.orderLines.length; i++) {
                itemsCount += this.cart.orderLines[i].quantity || 0;
            }
            return itemsCount;
        }
    },
};
Vue.createApp(bigCart).mount('#bigCart');

let productList = {
    data() {
        return {
            cart,
            products: [
                { id: 1, label: 'Product A' },
                { id: 2, label: 'Product B' },
                { id: 3, label: 'Product C' },
            ]
        }
    },
    methods: {
        addToCart(product) {
            const line = this.cart.orderLines.find(line => line.id === product.id);
            if (line) {
                line.quantity++;
            } else {
                this.cart.orderLines.push({ ...product, quantity: 1 });
            }          
        },
    }
};
Vue.createApp(productList).mount('#productList');
EN

回答 2

Stack Overflow用户

发布于 2022-03-13 14:51:04

在所有应用程序的外部使用一个反应性存储,并在需要的地方注入它。

您可以实现piniavuex。最简单的解决方案是一个reactive()对象。

下面是一个基本的例子,有3个单独的应用程序,演示了原理:

代码语言:javascript
复制
const { createApp, reactive, toRefs } = Vue;
const store = reactive({
  count: 0
})

createApp({
  setup: () => ({
    ...toRefs(store),
    increaseCount: () => store.count += 1
  })
}).mount('#app-1');

createApp({
  setup: () => ({
    ...toRefs(store),
    decreaseCount: () => store.count -= 1
  })
}).mount('#app-2');

createApp({
  setup: () => ({
    ...toRefs(store)
  })
}).mount('#app-3');
代码语言:javascript
复制
.container {
  display: flex;
  justify-content: space-evenly;
}
代码语言:javascript
复制
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<div class="container">
  <div id="app-1">
    <h3> App 1</h3>
    {{ count }}
    <button @click="increaseCount">Increase</button>
  </div>
  <div id="app-2">
    <h3> App 2</h3>
    {{ count }}
    <button @click="decreaseCount">Decrease</button>
  </div>
  <div id="app-3">
    <h3> App 3</h3>
    {{ count }}
    <input v-model.number="count" type="number">
  </div>
</div>

同样,使用pinia并在商店中放置increasedecrease方法:

代码语言:javascript
复制
const { createApp, reactive, toRefs } = Vue;
const { createPinia, defineStore } = Pinia;
const pinia = createPinia();

const useCounter = defineStore('counter', {
  state: () => ({
    count: 0
  }),
  actions: {
    increase() {
      this.count += 1;
    },
    decrease() {
      this.count -= 1;
    }
  }
});

[1, 2, 3].forEach(key => createApp({
  setup: () => ({
    counter: useCounter(pinia)
  })
}).mount(`#app-${key}`))
代码语言:javascript
复制
.container {
  display: flex;
  justify-content: space-evenly;
}
代码语言:javascript
复制
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<script src="https://unpkg.com/vue-demi"></script>
<script src="https://unpkg.com/pinia@2.0.11/dist/pinia.iife.prod.js"></script>
<div class="container">
  <div id="app-1">
    <h3> App 1</h3>
    {{ counter.count }}
    <button @click="counter.increase">Increase</button>
  </div>
  <div id="app-2">
    <h3> App 2</h3>
    {{ counter.count }}
    <button @click="counter.decrease">Decrease</button>
  </div>
  <div id="app-3">
    <h3> App 3</h3>
    {{ counter.count }}
    <input v-model.number="counter.count" type="number"/>
  </div>
</div>

Pinia和Vuex具有与vue devtools集成的优势,这意味着您可以检查更改(即.a)。突变),撤销或重播它们。基本上,它使调试变得简单多了。

票数 1
EN

Stack Overflow用户

发布于 2022-03-13 16:49:44

我分析了您在codepen中添加的代码。First of all,如果你是"vue.js“新手,我建议不要在应用程序的某些部分使用jQuery纯jsvue-js来构建这样的应用程序。因为这可能会引起一些你无法理解的冲突。

无论如何,这里的问题是:而不是考虑Vue reactivity。简单地说,当您使用Vue.createApp(...).mount("some id")时,only -- html代码中作为id子级的部分--由Vue访问和控制。因此,当您在该部分外有一个按钮时,您不能期望Vue识别并正确处理它。由于这个事实,如果您想用自己的itemsCount javascript代码更改一个数字(这里是数据)并立即在html部分(即Vue的反应性行为)中看到结果,那么您必须自己编写所有代码。例如,我在这里放了一些代码来说明我的意思:

代码语言:javascript
复制
let cart = { orderLines: [
    /* change the structure of defined array */
        {
            quantity: 0
        }
    ], itemsCount: 0 }


let addViaJs = document.querySelector('#addViaJs');
addViaJs.addEventListener('click', () => {
    /* manually change the "html" content with js codes */
    let currentValue = parseInt(document.getElementById("itemsSpan").innerText)

    cart.orderLines[0].quantity = currentValue + 1;
    cart.itemsCount = currentValue + 1;
    document.getElementById("itemsSpan").innerText = cart.itemsCount;
});

let miniCart = {
    data() {
        return {
            cart,
        }
    },
    computed: {
        /* this "itemsCount is different from "cart.itemsCount" */
        itemsCount() {
            let itemsCount = 0;
            for (let i = 0; i < this.cart.orderLines.length; i++) {
                itemsCount += this.cart.orderLines[i].quantity || 0;
            }
            return itemsCount;
        }
    },
};
Vue.createApp(miniCart).mount('#miniCart');

let bigCart = {
    data() {
        return {
            cart,
        }
    },
    computed: {
        itemsCount() {
            let itemsCount = 0;
            for (let i = 0; i < this.cart.orderLines.length; i++) {
                itemsCount += this.cart.orderLines[i].quantity || 0;
            }
            return itemsCount;
        }
    },
};
Vue.createApp(bigCart).mount('#bigCart');

let productList = {
    data() {
        return {
            cart,
            products: [
                { id: 1, label: 'Product A' },
                { id: 2, label: 'Product B' },
                { id: 3, label: 'Product C' },
            ]
        }
    },
    methods: {
        addToCart(product) {
            /* change the related values of "count" object */
            this.cart.orderLines[0].quantity++
            this.cart.itemsCount++
            // const line = this.cart.orderLines.find(line => line.id === product.id);
            // if (line) {
            //     line.quantity++;
            // } else {
            //     this.cart.orderLines.push({ ...product, quantity: 1 });
            // }
        },
    }
};
Vue.createApp(productList).mount('#productList');
代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    

<div id="productList" v-cloak>
    <h2>Products</h2>
    <div v-for="product in products">
        <span>{{ product.label }}</span>
        <button @click="addToCart(product)">Add</button>
    </div>
</div>

<div id="miniCart" v-cloak>
    <h2>Mini cart</h2>
    <div>itemsCount:
        <span id="itemsSpan">
            {{ itemsCount }}
        </span>
    </div>
</div>

<div id="bigCart" v-cloak>
<!--    <h2>Cart ({{ itemsCount }})</h2>-->
<!--    <ul>-->
<!--        <li v-for="line in cart.orderLines">{{ line.label}} ({{ line.quantity }})</li>-->
<!--    </ul>-->
</div>

<button id='addViaJs'>
    Add via JS (outside Vue)
</button>
    

<script src="https://unpkg.com/vue@3.2.31/dist/vue.global.js"></script>

    
</body>
</html>

这与您的代码并不完全类似。我评论了一些部分,并使数据更简单,以更好地显示结果。首先,我将cart数据的结构设置为必须在添加元素之后的结构(如果不向orderLines数组添加任何object,则javascript在添加例如orderLines.quantity的值时会给出错误)。之后,在addEventListener部件中,我从html部件获取内容,向它添加值,并将新值返回到html。如果您的按钮是vue应用程序的子程序,而不是外部的,那么所有这些进程都可以通过Vue处理。同样,在您的Vue部分中,您必须在需要的时候和地点更改cart.itemsCount和其他属性。

您还必须注意,您定义的itemsCount计算属性与cart.itemsCount完全不同,这不应导致代码中的错误。以上所有的描述,我上面说过,再次我不建议以这种方式构建您的应用程序。在这种情况下,您可能会在代码中遇到其他错误。您可以使用jQuerypure js更改数据(例如,cart.quantity),但是要在由 Vue 处理的html部件中显示数据,可以使用按钮和其他方法,这些方法本身并不在Vue之外,还可以监视Vue Devtools中数据的更改,以正确调试代码。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71456423

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档