Javascript 如何让具有多个值的子组件更新父数据

Javascript 如何让具有多个值的子组件更新父数据,javascript,vue.js,vuejs2,Javascript,Vue.js,Vuejs2,代码如下 我想我错过了一个关键的部分。我浏览了文档,一步一步地观看了整个vue2。到目前为止,一切都是有意义的,但我仍然停留在一个似乎是核心的部分上。任何帮助都将不胜感激。如果这是完全错误的,请让我知道,我没有结婚的任何东西 所需功能:有一个订单Vue实例,它有行项目 在order.mounted()上,我们找到了订单数据的api端点,包括可能存在的行项目。如果存在行项目,我们将设置该订单数据(this.lineitems=request.body.lineitems或类似)。这部分工作正常,我

代码如下

我想我错过了一个关键的部分。我浏览了文档,一步一步地观看了整个vue2。到目前为止,一切都是有意义的,但我仍然停留在一个似乎是核心的部分上。任何帮助都将不胜感激。如果这是完全错误的,请让我知道,我没有结婚的任何东西

所需功能:有一个
订单
Vue实例,它有
行项目

order.mounted()
上,我们找到了订单数据的api端点,包括可能存在的行项目。如果存在行项目,我们将设置该订单数据(
this.lineitems=request.body.lineitems
或类似)。这部分工作正常,我可以得到订单总数,因为此时订单的行项目是最新的

每个行项目都是一个带有数量和产品的可编辑表单。如果我更改任何行项目的数量或产品,我希望子行项目组件通知父组件它已更改,然后父组件将使用新值更新其自己的行项目数据数组,并使用所有当前行项目数据执行POST请求,以便服务器端可以计算新的行项目总数(许多特价、折扣等)。这将返回订单行项目数据的完整替换数组,该数组将传递给行项目以重新渲染

问题:

  • 行项目组件“update…”方法感觉显然是错误的,但我最大的问题是理解如何让父级使用新数据更新其自己的行项目数据数组
  • 如果第二个行项目更改为数量1,我如何使父级的行项目数据更改为数量1?我的主要问题是,我不知道父级如何知道它自己的哪些行项目数据数组需要修改,以及如何从更改的子级获取数据。我假设它是通过事件、通过发射传入的,但我现在知道了吗需要到处传递主键,这样我就可以循环和比较了?如果它是一个新的行项目,但还没有主键呢

  • 如上所述,我正在使用现有行项目的DB主键作为v-for键。如果我需要一个在现有行项目下追加空白行项目的“新行项目”,或者如果是一个没有主键的新订单,该怎么办?这通常是如何处理的

  • 是否有一种最佳的道具使用方法,而不是我的“初始…”风格?我假设只在
    v-on
    上直接使用$emit,但我不确定如何获得相关信息才能通过这种方式

  • 这似乎正是VueJS适合的任务,我只是觉得我一直在错误的方向上追逐我的尾巴。谢谢你的帮助

    行项目

    Vue.component('line-item', {
        props: ["initialQuantity", "initialProduct", "total"],
        data () {
            return {
                // There are more but limiting for example
                quantity: initialQuantity,
                product: initialProduct,
                productOptions = [
                    { id: 333, text: "Product A"},
                    { id: 555, text: "Product B"},
                    { id: 777, text: "Product C"},
                ]
            }
        },
        updateQuantity(event) {
            item = {
                quantity: event.target.value,
                product: this.product
            }
            this.$emit('update-item', item)
        },
        updateProduct(event) {
            item = {
                quantity: this.quantity,
                product: event.target.value
            }
            this.$emit('update-item', item)
        }
        template: `
            <input :value="quantity" type="number" @input="updateQuantity">
    
            <select :value="product" @input="updateProduct">
                <option v-for="option in productOptions" v-bind:value="option.id"> {{ option.text }} </option>
            </select>
    
            Line Item Price: {{ total }}
            <hr />
        `
    })
    
    Vue.component('line-item'{
    道具:[“初始数量”、“初始产品”、“总计”],
    数据(){
    返回{
    //有更多,但限制,例如
    数量:初始数量,
    产品:首字母产品,
    productOptions=[
    {id:333,文本:“产品A”},
    {id:555,文本:“产品B”},
    {id:777,文本:“产品C”},
    ]
    }
    },
    updateQuantity(事件){
    项目={
    数量:event.target.value,
    产品:这个产品
    }
    此.$emit('update-item',item)
    },
    updateProduct(事件){
    项目={
    数量:这个,数量,
    产品:event.target.value
    }
    此.$emit('update-item',item)
    }
    模板:`
    {{option.text}
    行项目价格:{{total}
    
    ` })
    订单/应用程序

    var order = new Vue({
        el: '#app',
        data: {
            orderPK: orderPK,
            lineitems: []
        },
        mounted() {
            this.fetchLineItems()
        },
        computed: {
            total() {
                // This should sum the line items, like (li.total for li in this.lineitems)
                return 0.0
        },
        methods: {
            updateOrder(item) {
                // First, somehow update this.lineitems with the passed in item, then
                fetch(`domain.com/orders/${this.orderPK}/calculate`, this.lineitems)
                    .then(resp => resp.json())
                    .then(data => {
                        this.lineitems = data.lineitems;
                    })
            },
            fetchLineItems() {
                fetch(`domain.com/api/orders/${this.orderPK}`)
                    .then(resp => resp.json())
                    .then(data => {
                        this.lineitems = data.lineitems;
                    })
            },
        },
        template: `
            <div>
                <h2 id="total">Order total: {{ total }}</h2>
    
                <line-item v-for="item in lineitems"
                    @update-item="updateOrder"
                    :key="item.id"
                    :quantity="item.quantity"
                    :product="item.product"
                    :total="item.total"
                    ></line-item>
            </div>
        `
    })
    
    var顺序=新的Vue({
    el:“#应用程序”,
    数据:{
    orderPK:orderPK,
    行项目:[]
    },
    安装的(){
    this.fetchLineItems()
    },
    计算:{
    总数(){
    //这应该是行项目的总和,如(此.lineitems中li的li.total)
    返回0.0
    },
    方法:{
    更新顺序(项目){
    //首先,用传入的项更新this.lineitems,然后
    fetch(`domain.com/orders/${this.orderPK}/calculate`,this.lineitems)
    .then(resp=>resp.json())
    。然后(数据=>{
    this.lineitems=data.lineitems;
    })
    },
    fetchLineItems(){
    fetch(`domain.com/api/orders/${this.orderPK}`)
    .then(resp=>resp.json())
    。然后(数据=>{
    this.lineitems=data.lineitems;
    })
    },
    },
    模板:`
    订单总数:{{total}
    `
    })
    
    以下是您尝试中的问题列表,这些问题可能会阻止它显示任何内容,例如:

  • quantity:initialQuantity
    ,-对于所有其他此类数据,您肯定是指
    quantity:this.initialQuantity
    ,…等等
  • 计算总数缺少
    }
  • 您的
    行项目
    模板无效-您有多个“根”元素
  • 还有一些小问题:

  • 您需要的是select的
    @change
    处理程序,而不是
    @input
    ,如果您的代码运行,您会看到差异
  • 类似地,您希望输入
    @change
    ,否则每次击键都会发出获取请求来更改项目,这可能不是您想要的
  • 所以,尽管如此,我还是制作了一些工作代码,可以满足您的所有需求——不过,公平地说,主要是为了我自己的“学习”:p

    //*******一些模拟回迁的虚拟数据和函数
    常数乘积=[
    {id:333,正文:“产品A”,单价:10},
    {id:555,正文:“产品B”,单价:11},
    {id:777,文本:“产品”
    
    var order = new Vue({
        el: '#app',
        data: {
            orderPK: orderPK,
            lineitems: []
        },
        mounted() {
            this.fetchLineItems()
        },
        computed: {
            total() {
                // This should sum the line items, like (li.total for li in this.lineitems)
                return 0.0
        },
        methods: {
            updateOrder(item) {
                // First, somehow update this.lineitems with the passed in item, then
                fetch(`domain.com/orders/${this.orderPK}/calculate`, this.lineitems)
                    .then(resp => resp.json())
                    .then(data => {
                        this.lineitems = data.lineitems;
                    })
            },
            fetchLineItems() {
                fetch(`domain.com/api/orders/${this.orderPK}`)
                    .then(resp => resp.json())
                    .then(data => {
                        this.lineitems = data.lineitems;
                    })
            },
        },
        template: `
            <div>
                <h2 id="total">Order total: {{ total }}</h2>
    
                <line-item v-for="item in lineitems"
                    @update-item="updateOrder"
                    :key="item.id"
                    :quantity="item.quantity"
                    :product="item.product"
                    :total="item.total"
                    ></line-item>
            </div>
        `
    })