刚接触vue不久,对里面的data和计算属性的使用有点疑惑,在跟着某视频学习Vue的过程中,产生了疑问。
想实现这样的效果
代码如下
App.vue的代码
<template>
<div id="app">
<topbar class="topbar"></topbar>
<main>
<editor :resume="resume" class="editor" />
<preview :resume="resume" class="preview" />
</main>
</div>
</template>
<script>
import Topbar from './components/Topbar'
import Editor from './components/Editor'
import Preview from './components/Preview'
export default {
components: {
Topbar,
Editor,
Preview
},
data:function(){
return {
resume:{
profile: {
name: '',
city: '',
birth: ''
},
careers: [
{ company: '', content: '' }
],
labelsForCareers: [
'公司', '工作内容'
],
titleForCareers: '工作经历',
educationHistory: [
{ school: '', duration: '', degree: '' }
],
labelsForEducationHistory: [
'学校', '时长', '学位'
],
titleForEducationHistory: '教育背景',
projects: [
{ project: '', content: '' }
],
labelsForProjects: [
'项目名称', '具体描述'
],
titleForProjects: '项目经历',
awards: [{
name: ''
}],
labelsForAwards: ['获奖名称'],
titleForAwards: '所获奖项',
contacts:{
qq:'',
wx:'',
phone:'',
github:'',
email:''
}
}
}
}
}
</script>
然后是Editor.vue
<template>
<div id="editor">
<nav>
<ol>
<li v-for="(item,index) in items" :class="{active:currentTab === index }" @click="currentTab = index" :key="index">
<svg class="icon">
<use :xlink:href="item"></use>
</svg>
</li>
</ol>
</nav>
<ol class="panes">
<!-- li{tab $} *6 -->
<li v-if="currentTab === 0">
<profile-editor :profile="resume.profile"></profile-editor>
</li>
<li v-if="currentTab === 1">
<common-editor :items="resume.careers" :labels="resume.labelsForCareers" :title="resume.titleForCareers"></common-editor>
</li>
<li v-if="currentTab === 2">
<common-editor :items="resume.educationHistory" :labels="resume.labelsForEducationHistory" :title="resume.titleForEducationHistory"></common-editor>
</li>
<li v-if="currentTab === 3">
<common-editor :items="resume.projects" :labels="resume.labelsForProjects" :title="resume.titleForProjects"></common-editor>
</li>
<li v-if="currentTab === 4">
<common-editor :items="resume.awards" :labels="resume.labelsForAwards" :title="resume.titleForAwards"></common-editor>
</li>
<li v-if="currentTab === 5">
<h2> 个人信息</h2>
<el-form label-position="top" label-width="80px">
<el-form-item label="QQ">
<el-input v-model="resume.contacts.qq"></el-input>
</el-form-item>
<el-form-item label="WeChat">
<el-input v-model="resume.contacts.wx"></el-input>
</el-form-item>
<el-form-item label="Email">
<el-input v-model="resume.contacts.email"></el-input>
</el-form-item>
<el-form-item label="Phone">
<el-input v-model="resume.contacts.phone"></el-input>
</el-form-item>
<el-form-item label="Github">
<el-input v-model="resume.contacts.github"></el-input>
</el-form-item>
</el-form>
</li>
</ol>
</div>
</template>
<script>
import ProfileEditor from './ProfileEditor'
import CommonEditor from './CommonEditor'
export default {
props:['resume'],
components: { ProfileEditor, CommonEditor },
data: function() {
return {
currentTab: 0,
items: ["#icon-card", "#icon-handbag", "#icon-book", "#icon-heart", "#icon-cup", "#icon-phone"],
contents: ["Tab1", "Tab2", "Tab3", "Tab4", "Tab5", "Tab6"],
}
}
}
</script>
最后是CommonEditor.vue
<template>
<div>
<h2>{{title}}</h2>
<el-form>
<div v-for="(item,index) in copyItems" :key="index" class="container">
<el-form-item :label="labels[index]" v-for="(key,index) in keys" :key="index">
<el-input v-model="item[key]"></el-input>
</el-form-item>
<i class="el-icon-close" @click="remove(index)"></i>
</div>
<el-button type="primary" @click="add">添加</el-button>
</el-form>
</div>
</template>
<script>
export default {
props: ['items', 'labels', 'title'],
computed: {
keys: function() {
return Object.keys(this.items[0])
},
// copyItems: function() {
// return this.items.slice(0)
// }
},
data: function() {
return {
copyItems: this.items.slice(0)
}
},
methods: {
add: function() {
let temp = {}
this.keys.map((key) => {
temp[key] = ''
})
this.copyItems.push(temp)
},
remove: function(index) {
this.copyItems.splice(index, 1)
}
}
}
</script>
问题来了
- 上面的代码存在严重问题,我在工作经历这一项点击添加按钮,却发现此时关系到CommonEditor.vue的部分也增加了。效果如下:
我明明是在“工作经历”里面点击的添加,为什么当我切换到“所获奖项”这部分的时候,里面也变为了两项?为什么似乎这几个部分的copyItems是同一个copyItems?
- 然后我试了不用data而使用computed属性,即:
computed: {
keys: function() {
return Object.keys(this.items[0])
},
copyItems: function() {
return this.items.slice(0)
}
},
// data: function() {
// return {
// copyItems: this.items.slice(0)
// }
// },
这下两个按钮(添加和那个x按钮)点击都没反应了。我想问是不是computed属性里面的响应式数据的改变而引起的视图的更新所只与他们依赖的东西有关?以上面的例子为例,copyItems是不是就只与this.items有关?因为我通过console.log发现,点击“添加”按钮之后,add函数执行了,copyItems确实发生了变化,但是视图却没有发生相应的变化。这是为什么呢?
在这两个问题上卡了很久了,希望有人能解答。
解决办法,给下面这些结构相同添加
key
属性这种切换情况下,结构属性完全相同的标签,
vue
会自动复用,加key
可以指明他们是不同的,阻止复用。在
commonEditor.vue
里的这里加上
{{item}}
,在工作经历里点完添加,切换至所获奖项,你也能看到,所渲染出来的item是也是组件复用的结果
参考链接