Vue 2 组件在循环中访问循环 - instance/scope 问题
Vue 2 Component Access Loop within a Loop - instance/scope issue
我正在制作我的第一个 Vue 2 组件(在 Laravel 5.3 应用程序中),但是 运行 变成了一个 instance/scope 问题,我花了几个小时试图解决这个问题,但就是无法解决它开始工作了!
我的组件生成一个订单列表,每个订单中都有一个用户(顾问)列表。我希望能够 select 一个用户的订单,然后将用户分配给该订单。
我的组件的最新版本如下所示;
Vue.component('unassigned-orders', {
template: `
<table id="assignOrder" class="table table-hover">
<thead>
// table headers
</thead>
<tr v-for="(unassignedOrder, key) in unassignedOrders"
:key="unassignedOrder.order_id">
<td>{{ unassignedOrder.order_id }}</td>
<td>{{ unassignedOrder.first_name }} {{ unassignedOrder.last_name }}</td>
<td>{{ unassignedOrder.order_status }}</td>
<td><select @change="assignAdvisor()">
<option v-for="advisor in advisors" :value="advisor.id" >
{{ advisor.first_name }} {{ advisor.last_name }}
</option>
</select></td>
<td><a class="btn btn-default">
Set Advisor {{ unassignedOrder.assignTo }}</a></td>
</tr>
</table>`,
data: function() {
return {
unassignedOrders: [{'assignTo' : ''}],
advisors: ''
}
},
methods: {
assignAdvisor: function() {
this.assignTo = event.target.value;
}
},
mounted() {
axios.get('url').then(response => this.advisors = response.data);
axios.get('url').then(response => this.unassignedOrders = response.data);
}
});
我没有收到任何错误,但该功能不起作用(我只需要将 var assignTo
更新为相关订单,我相信我能解决其余的问题)。
我确定我遗漏了一些非常简单的东西,有人有任何指示吗?
谢谢
可能未分配 Order 和 Advisor 是具有自己的 getter 和 setter 的复杂组件,因此您可以尝试为它们使用计算属性或观察器。
在您的问题评论中进行一些讨论后,我们能够将您的问题分解为:
- 您正在呈现项目列表。这个列表是一个对象数组。
- 呈现的项目中有一些功能允许您更改数组中的相应对象。
但是怎么可能更新数组中对应的对象呢?
下面是一个演示解决方案的片段。
const items = {
template: `
<div>
<ul>
<li v-for="(item, index) in proxyItems">
{{ item.name }} - {{ item.option }}
<select @change="change(index, $event.target.value)">
<option>No option</option>
<option>Option 1</option>
<option>Option 2</option>
</select>
</li>
<ul>
</div>
`,
props: {
items: {
type: Array,
},
},
data() {
return {
proxyItems: this.items,
};
},
methods: {
change(index, value) {
this.proxyItems.splice(index, 1, { ...{}, ...this.proxyItems[index], ...{ option: value } });
console.log(this.proxyItems);
},
},
};
new Vue({
render(createElement) {
const props = {
items: [
{ name: 'Item 1', option: 'No option' },
{ name: 'Item 2', option: 'No option' },
],
};
return createElement(items, { props });
},
}).$mount('#app');
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div id="app"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.js"></script>
</body>
</html>
这里是解决方案的概要:
- 要更新数组,我们需要找到您要更新的项目的索引,然后更新它。
this.proxyItems.splice(index, 1, { ...{}, ...this.proxyItems[index], ...{ option: value } });
- 组件实际上是将项目作为值传递给道具
items
,但是不建议您直接改变道具
In addition, every time the parent component is updated, all props in the child component will be refreshed with the latest value. This means you should not attempt to mutate a prop inside a child component. If you do, Vue will warn you in the console.
– https://vuejs.org/v2/guide/components.html#One-Way-Data-Flow
因此我们在组件的数据方法中创建项目的代理。
{
props: {
items: {
type: Array,
},
},
data() {
return {
proxyItems: this.items,
};
},
}
items
中的所有数据突变将发生在proxyItems
中。
希望以上内容能帮助您解决问题。但是我会提出一个建议:
It may be better to break down your list items into their own components. This will mean every item will have their own scope, you won't have to proxy the items and you won't have to do complicated splicing and object creation with spread.
下面是一个例子。
const item = {
template: `
<li>
{{ name }} - {{ selectedOption }}
<select @change="change($event.target.value)">
<option>No option</option>
<option>Option 1</option>
<option>Option 2</option>
</select>
</li>
`,
props: ['name'],
data() {
return {
selectedOption: 'No option',
};
},
methods: {
change(value) {
this.selectedOption = value;
console.log(this.selectedOption);
},
},
};
const items = {
components: {
item,
},
template: `
<div>
<ul>
<item v-for="item in items" :name="item.name"></item>
<ul>
</div>
`,
props: {
items: {
type: Array,
},
},
};
new Vue({
render(createElement) {
const props = {
items: [
{ name: 'Item 1', option: 'No option' },
{ name: 'Item 2', option: 'No option' },
],
};
return createElement(items, { props });
},
}).$mount('#app');
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div id="app"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.js"></script>
</body>
</html>
我正在制作我的第一个 Vue 2 组件(在 Laravel 5.3 应用程序中),但是 运行 变成了一个 instance/scope 问题,我花了几个小时试图解决这个问题,但就是无法解决它开始工作了!
我的组件生成一个订单列表,每个订单中都有一个用户(顾问)列表。我希望能够 select 一个用户的订单,然后将用户分配给该订单。
我的组件的最新版本如下所示;
Vue.component('unassigned-orders', {
template: `
<table id="assignOrder" class="table table-hover">
<thead>
// table headers
</thead>
<tr v-for="(unassignedOrder, key) in unassignedOrders"
:key="unassignedOrder.order_id">
<td>{{ unassignedOrder.order_id }}</td>
<td>{{ unassignedOrder.first_name }} {{ unassignedOrder.last_name }}</td>
<td>{{ unassignedOrder.order_status }}</td>
<td><select @change="assignAdvisor()">
<option v-for="advisor in advisors" :value="advisor.id" >
{{ advisor.first_name }} {{ advisor.last_name }}
</option>
</select></td>
<td><a class="btn btn-default">
Set Advisor {{ unassignedOrder.assignTo }}</a></td>
</tr>
</table>`,
data: function() {
return {
unassignedOrders: [{'assignTo' : ''}],
advisors: ''
}
},
methods: {
assignAdvisor: function() {
this.assignTo = event.target.value;
}
},
mounted() {
axios.get('url').then(response => this.advisors = response.data);
axios.get('url').then(response => this.unassignedOrders = response.data);
}
});
我没有收到任何错误,但该功能不起作用(我只需要将 var assignTo
更新为相关订单,我相信我能解决其余的问题)。
我确定我遗漏了一些非常简单的东西,有人有任何指示吗?
谢谢
可能未分配 Order 和 Advisor 是具有自己的 getter 和 setter 的复杂组件,因此您可以尝试为它们使用计算属性或观察器。
在您的问题评论中进行一些讨论后,我们能够将您的问题分解为:
- 您正在呈现项目列表。这个列表是一个对象数组。
- 呈现的项目中有一些功能允许您更改数组中的相应对象。
但是怎么可能更新数组中对应的对象呢?
下面是一个演示解决方案的片段。
const items = {
template: `
<div>
<ul>
<li v-for="(item, index) in proxyItems">
{{ item.name }} - {{ item.option }}
<select @change="change(index, $event.target.value)">
<option>No option</option>
<option>Option 1</option>
<option>Option 2</option>
</select>
</li>
<ul>
</div>
`,
props: {
items: {
type: Array,
},
},
data() {
return {
proxyItems: this.items,
};
},
methods: {
change(index, value) {
this.proxyItems.splice(index, 1, { ...{}, ...this.proxyItems[index], ...{ option: value } });
console.log(this.proxyItems);
},
},
};
new Vue({
render(createElement) {
const props = {
items: [
{ name: 'Item 1', option: 'No option' },
{ name: 'Item 2', option: 'No option' },
],
};
return createElement(items, { props });
},
}).$mount('#app');
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div id="app"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.js"></script>
</body>
</html>
这里是解决方案的概要:
- 要更新数组,我们需要找到您要更新的项目的索引,然后更新它。
this.proxyItems.splice(index, 1, { ...{}, ...this.proxyItems[index], ...{ option: value } });
- 组件实际上是将项目作为值传递给道具
items
,但是不建议您直接改变道具
In addition, every time the parent component is updated, all props in the child component will be refreshed with the latest value. This means you should not attempt to mutate a prop inside a child component. If you do, Vue will warn you in the console.
– https://vuejs.org/v2/guide/components.html#One-Way-Data-Flow
因此我们在组件的数据方法中创建项目的代理。
{
props: {
items: {
type: Array,
},
},
data() {
return {
proxyItems: this.items,
};
},
}
items
中的所有数据突变将发生在proxyItems
中。
希望以上内容能帮助您解决问题。但是我会提出一个建议:
It may be better to break down your list items into their own components. This will mean every item will have their own scope, you won't have to proxy the items and you won't have to do complicated splicing and object creation with spread.
下面是一个例子。
const item = {
template: `
<li>
{{ name }} - {{ selectedOption }}
<select @change="change($event.target.value)">
<option>No option</option>
<option>Option 1</option>
<option>Option 2</option>
</select>
</li>
`,
props: ['name'],
data() {
return {
selectedOption: 'No option',
};
},
methods: {
change(value) {
this.selectedOption = value;
console.log(this.selectedOption);
},
},
};
const items = {
components: {
item,
},
template: `
<div>
<ul>
<item v-for="item in items" :name="item.name"></item>
<ul>
</div>
`,
props: {
items: {
type: Array,
},
},
};
new Vue({
render(createElement) {
const props = {
items: [
{ name: 'Item 1', option: 'No option' },
{ name: 'Item 2', option: 'No option' },
],
};
return createElement(items, { props });
},
}).$mount('#app');
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div id="app"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.js"></script>
</body>
</html>