我正在实现一个用户配置文件编辑页面,该页面最初包含从vuex
存储中加载的数据。然后,用户可以自由编辑他的数据并将其最终存储在商店中。
由于用户还可以单击取消按钮以恢复到其原始状态,所以我决定为从商店中获取的用户数据创建一个“本地”视图副本。这些数据将保留在视图中,并且当用户按保存时,它们将被保存在商店中。
视图如下:
<template class="user-profile">
<v-form>
<template v-if="profile.avatar">
<div class="text-center">
<v-avatar width="120" height="120">
<img
:src="profile.avatar"
:alt="profile.firstname"
>
</v-avatar>
</div>
</template>
<div class="text-center mt-4">
<v-btn
color="primary"
dark
@click.stop="showImageDialog=true"
>
Change Image
</v-btn>
</div>
<v-row>
<v-col>
<v-text-field
label="First name"
single-line
disabled
v-model="profile.firstname"
></v-text-field>
</v-col>
<v-col>
<v-text-field
label="Last name"
single-line
disabled
v-model="profile.lastname"
></v-text-field>
</v-col>
</v-row>
<v-text-field
label="Email"
single-line
v-model="profile.email"
></v-text-field>
<v-text-field
id="title"
label="Title"
single-line
v-model="profile.title"
></v-text-field>
<v-textarea
no-resize
clearable
label="Biography"
v-model="profile.bio"
></v-textarea>
<v-dialog
max-width="500"
v-model="showImageDialog"
>
<v-card>
<v-card-title>
Update your profile picture
</v-card-title>
<v-card-text>
<v-file-input @change="setImage" accept="image/*"></v-file-input>
<template v-if="userAvatarExists">
<vue-cropper
ref="cropper"
:aspect-ratio="16 / 9"
:src="profile.avatar"
/>
</template>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
color="green darken-1"
text
@click="showImageDialog=false"
>
Cancel
</v-btn>
<v-btn
color="green darken-1"
text
@click="uploadImage"
>
Upload
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<div class="mt-8">
<v-btn @click="onUpdateUser">Update</v-btn>
</div>
</v-form>
</template>
<script>
import { mapGetters, mapActions } from 'vuex'
import VueCropper from 'vue-cropperjs';
import 'cropperjs/dist/cropper.css';
export default {
components: { VueCropper},
mounted() {
this.profile = this.getUserProfile ? this.getUserProfile : {}
},
data() {
return {
profile: {},
avatar: null,
userAvatarExists: false,
showImageDialog: false,
}
},
watch: {
getUserProfile(newData){
this.profile = newData;
},
deep: true
},
computed: {
...mapGetters({
getUserProfile: 'user/me',
})
},
methods: {
...mapActions({
storeAvatar: 'user/storeAvatar',
updateUser: 'user/update'
}),
onUpdateUser() {
const data = {
id: this.profile.id,
email: this.profile.email,
title: this.profile.title,
bio: this.profile.bio,
avatar: this.profile.avatar,
}
this.updateUser(data)
},
uploadImage() {
this.$refs.cropper.getCroppedCanvas().toBlob((blob => {
this.storeAvatar(blob).then((filename => {
this.profile.avatar = filename.data
this.$refs.cropper.reset()
}));
this.showImageDialog = false
}));
},
setImage(file) {
this.userAvatarExists = true;
if (file.type.indexOf('image/') === -1) {
alert('Please select an image file');
return;
}
if (typeof FileReader === 'function') {
const reader = new FileReader();
reader.onload = (event) => {
this.$refs.cropper.replace(event.target.result);
};
reader.readAsDataURL(file);
} else {
alert('Sorry, FileReader API not supported');
}
}
}
}
</script>
问题/问题:
v-if="profile.avatar"
。问题是在profile.avatar
功能中设置uploadImage
,模板看不到此更改,因此不会渲染任何图像。但是,如果我更改代码,使profile.avatar
变为只是avatar
(不再位于profile
对象中),模板开始查看更改并渲染图像正确地。为什么这样?它与制作一个从商店复制watch
功能?mounted
功能中看到,我正在设置profile
基于getUserProfile
吸气剂的值。这是因为切换时似乎没有再次调用watch
功能路线。还有其他方法吗?该问题归因于数据属性的反应性
您已使用个人资料作为对象,默认情况下它没有任何属性,例如头像或名字,只是空的]]
在vue js中,如果要声明对象,则声明中的关键内容只是反应性的一部分。配置文件中的键一旦更改,它就会重新渲染模板
但是您仍然可以使用$ set将新属性添加到数据属性对象中>
在您声明的数据中说个人资料:{}
如果要在运行时使用中将头像设置为新的反应性属性
this.$set(this.profile, key, value)
是
this.$set(this.profile, avatar, imageData)
在上面的代码中,setIuploadImage函数
uploadImage() { var self = this; self.$refs.cropper.getCroppedCanvas().toBlob((blob => { self.storeAvatar(blob).then((filename => { self.$set(self.profile, "avatar", filename.data) self.$refs.cropper.reset() })); self.showImageDialog = false })); },
这在vuejs中的arrow函数中不起作用,因此仅将this保留在另一个变量“ self”中,并在arrow函数中使用]]
也已装入函数中,如果this.getUserProfile返回空对象
,则按照javascript,空对象始终是真实的,直接将对象分配给配置文件不会使对象成为反应对象
mounted() { this.profile = this.getUserProfile ? this.getUserProfile : {} },
上面的代码可以写成
mounted() { if (this.getUserProfile && Object.keys(this.getUserProfile).length) { var self = this; Object.keys(this.getUserProfile).map(key => { self.$set(self.profile, key, self.getUserProfile[key]) }); } else { this.profile = {}; } }