javascript - VueJS - 查看模型、孩子和更新值
问题描述
我正在尝试学习 VueJS,但遇到了一个非常基本的问题。我在 Knockout 和 Mustache 方面有很多经验,我认为这可能是导致我出现问题的原因。
我正在尝试构建一个简单的复选框列表来使用绑定,但我的模型没有更新,并且我在控制台中收到以下警告:
避免直接改变 prop,因为只要父组件重新渲染,该值就会被覆盖。相反,使用基于道具值的数据或计算属性。道具被变异:'checked'
这是我正在尝试做的事情;
一个表示待办事项的简单视图模型:
function vmToDoItem(id, title){
this.id = id;
this.title = title;
this.complete = false;
}
一个表示所有待办事项的简单视图模型:
function vmToDo(items){
var self = this;
self.currentFilter = 'all';
self.items = items || [];
self.filters = {
all: function(){
return self.items;
},
active: function(){
return self.items.filter((item) => !item.complete);
},
complete: function(){
return self.items.filter((item) => item.complete);
}
}
}
表示待办事项的组件:
Vue.component('checkbox-item',
{
props: ['text', 'checked'],
template: '#checkbox-item-template',
computed: {
prefix: function(){
return !this.checked ? 'fa-circle' : 'fa-check-circle';
}
},
methods: {
clicked: function(){
this.checked = !this.checked;
}
}
})
对应的模板:
<script type="text/x-template" id="checkbox-item-template">
<span @click="clicked">
<span :class="'far ' + prefix"></span>
{{ text }}
</span>
</script>
“应用程序”的标记:
<div id="app">
<checkbox-item
v-for="item in items"
class="todoItem"
:key="item.id"
v-bind:text="item.title"
v-bind:checked="item.complete">
</checkbox-item>
<br />
<span>Items unchecked: {{ remaining }}</span>
</div>
初始化代码:
var mdl = new vmToDo();
mdl.items.push(new vmToDoItem(1, 'test 1'));
mdl.items.push(new vmToDoItem(2, 'test 2'));
var vm = new Vue({
el: '#app',
data: mdl,
computed: {
remaining: function(){
let currentFilter = this.$data.filters[this.$data.currentFilter];
return currentFilter().length;
}
}
});
一切都很好,单击其中一个项目可以正确切换复选框,但是 mdl.items 中的基础项目没有更新,我在控制台中收到上述警告。
我怀疑双向绑定的工作方式与我预期的不同,我预计它会像 Knockout 一样运行,但我不知道如何按照我预期的方式实现此功能。
为简洁起见,这里是我的问题的完整片段:
function vmToDoItem(id, title){
this.id = id;
this.title = title;
this.complete = false;
}
function vmToDo(items){
var self = this;
self.currentFilter = 'all';
self.items = items || [];
self.filters = {
all: function(){
return self.items;
},
active: function(){
return self.items.filter((item) => !item.complete);
},
complete: function(){
return self.items.filter((item) => item.complete);
}
}
}
Vue.component('checkbox-item',
{
props: ['text', 'checked'],
template: '#checkbox-item-template',
computed: {
prefix: function(){
return !this.checked ? 'fa-circle' : 'fa-check-circle';
}
},
methods: {
clicked: function(){
this.checked = !this.checked;
}
}
})
var mdl = new vmToDo();
mdl.items.push(new vmToDoItem(1, 'test 1'));
mdl.items.push(new vmToDoItem(2, 'test 2'));
var vm = new Vue({
el: '#app',
data: mdl,
computed: {
remaining: function(){
let currentFilter = this.$data.filters[this.$data.currentFilter];
return currentFilter().length;
}
}
});
#app span.todoItem{
display: inline-block;
cursor: pointer;
padding-right: 1em;
}
#app span.todoItem span.far {
vertical-align: middle;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<link rel="stylesheet" href="//use.fontawesome.com/releases/v5.6.3/css/regular.css" />
<link rel="stylesheet" href="//use.fontawesome.com/releases/v5.6.3/css/fontawesome.css" />
<div id="app">
<checkbox-item
v-for="item in items"
class="todoItem"
:key="item.id"
v-bind:text="item.title"
v-bind:checked="item.complete">
</checkbox-item>
<br />
<span>Items unchecked: {{ remaining }}</span>
</div>
<script type="text/x-template" id="checkbox-item-template">
<span @click="clicked">
<span :class="'far ' + prefix"></span>
{{ text }}
</span>
</script>
解决方案
“道具向下,事件向上”是要记住的规则。数据通过 props 从父级传递给子级。事件由孩子发出并由父母处理(事件向上不是一个严格的规则,但它是变化应该向上树的唯一方式)。在这种情况下,与其尝试为您的 prop 分配值,不如checked
发出一个事件并在组件上放置一个处理程序,以便父级将捕获该事件并采取相应的行动:
<checkbox-item v-for="item in items" class="todoItem" :key="item.id" :text="item.title" :checked="item.complete" @click="item.complete = !item.complete">
</checkbox-item>
我修改了您的代码段以这种方式工作,并列出了 item.complete 的值,以便您可以看到正在发生的数据更新。
function vmToDoItem(id, title) {
this.id = id;
this.title = title;
this.complete = false;
}
function vmToDo(items) {
var self = this;
self.currentFilter = 'all';
self.items = items || [];
self.filters = {
all: function() {
return self.items;
},
active: function() {
return self.items.filter((item) => !item.complete);
},
complete: function() {
return self.items.filter((item) => item.complete);
}
}
}
Vue.component('checkbox-item', {
props: ['text', 'checked'],
template: '#checkbox-item-template',
computed: {
prefix: function() {
return !this.checked ? 'fa-circle' : 'fa-check-circle';
}
},
methods: {
clicked: function() {
this.$emit('click');
}
}
})
var mdl = new vmToDo();
mdl.items.push(new vmToDoItem(1, 'test 1'));
mdl.items.push(new vmToDoItem(2, 'test 2'));
var vm = new Vue({
el: '#app',
data: mdl,
computed: {
remaining: function() {
let currentFilter = this.$data.filters[this.$data.currentFilter];
return currentFilter().length;
}
}
});
#app span.todoItem {
display: inline-block;
cursor: pointer;
padding-right: 1em;
}
#app span.todoItem span.far {
vertical-align: middle;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<link rel="stylesheet" href="//use.fontawesome.com/releases/v5.6.3/css/regular.css" />
<link rel="stylesheet" href="//use.fontawesome.com/releases/v5.6.3/css/fontawesome.css" />
<div id="app">
<checkbox-item v-for="item in items" class="todoItem" :key="item.id" :text="item.title" :checked="item.complete" @click="item.complete = !item.complete">
</checkbox-item>
<br />
<span>Items unchecked: {{ remaining }}</span>
<div v-for="item in items">
{{item.complete}}
</div>
</div>
<script type="text/x-template" id="checkbox-item-template">
<span @click="clicked">
<span :class="'far ' + prefix"></span> {{ text }}
</span>
</script>
推荐阅读
- appium-android - centos8 install appium failed:errno ENOENT appium-windows-driver@1.18.1 install: `node install-npm.js`
- angular - Angular 路由页面成功但未显示 html 内容
- python - python显示一个实际上并不存在的错误
- dart - 在飞镖扩展名中有什么好处?
- powerbi - Power BI 中每个组中的筛选、分组依据和计算唯一值
- c - 我应该如何修改我的代码以不输出为 0?
- android - 如何在android中实现带有单位增加的虚线进度条
- azure-devops - 在 azure devops 仪表板上显示较少的代码覆盖率
- android - 输入'未来
' 不是类型 'List 的子类型 ? - c# - Xamarin Forms & Firebase Realtime Database:如果用户名已经存在,如何拒绝用户注册