Vue.js 从Vuex存储的本地副本更新数据
我正在实现一个用户配置文件编辑页面,该页面最初由从Vue.js 从Vuex存储的本地副本更新数据,vue.js,vuejs2,vuex,Vue.js,Vuejs2,Vuex,我正在实现一个用户配置文件编辑页面,该页面最初由从vuex存储加载的数据组成。然后,用户可以自由编辑其数据,并最终将其存储在存储区中 由于用户也可以单击“取消”按钮恢复到其原始状态,因此我决定创建从存储中获取的用户数据的“本地”视图副本。这些数据将保存在视图中,一旦用户按下save,它们将保存在存储中 视图如下所示: <template class="user-profile"> <v-form> <template v-if="profile.avat
vuex
存储加载的数据组成。然后,用户可以自由编辑其数据,并最终将其存储在存储区中
由于用户也可以单击“取消”按钮恢复到其原始状态,因此我决定创建从存储中获取的用户数据的“本地”视图副本。这些数据将保存在视图中,一旦用户按下save,它们将保存在存储中
视图如下所示:
<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>
改变形象
更新您的个人资料图片
取消
上传
更新
从“vuex”导入{MapGetter,mapActions}
从“vue cropperjs”导入VueCropper;
导入“croperjs/dist/croper.css”;
导出默认值{
组件:{VueCropper},
安装的(){
this.profile=this.getUserProfile?this.getUserProfile:{}
},
数据(){
返回{
档案:{},
阿凡达:空,
用户:错,
showImageDialog:false,
}
},
观察:{
getUserProfile(新数据){
this.profile=newData;
},
深:是的
},
计算:{
…地图绘制者({
getUserProfile:'user/me',
})
},
方法:{
…映射操作({
storeAvatar:'用户/storeAvatar',
updateUser:'用户/更新'
}),
onUpdate用户(){
常数数据={
id:this.profile.id,
电子邮件:this.profile.email,
标题:this.profile.title,
bio:this.profile.bio,
阿凡达:这个.profile.avatar,
}
this.updateUser(数据)
},
上传图像(){
这是.$refs.crapper.getcrappedcanvas().toBlob((blob=>{
这个.storeAvatar(blob).then((文件名=>{
this.profile.avatar=filename.data
这是。$refs.crapper.reset()
}));
this.showImageDialog=false
}));
},
setImage(文件){
this.userAvatarExists=true;
if(file.type.indexOf('image/')=-1){
警报(“请选择图像文件”);
返回;
}
if(文件读取器的类型=='function'){
const reader=new FileReader();
reader.onload=(事件)=>{
这是.refs.croper.replace(event.target.result);
};
reader.readAsDataURL(文件);
}否则{
警报(“对不起,不支持FileReader API”);
}
}
}
}
议题/问题:
图片,图像应基于
v-if=“profile.avatar”
。问题是
profile.avatar
是在uploadImage
功能中设置的
模板未看到此更改,并且未渲染任何图像。
但是,如果我更改代码,使profile.avatar
变为
只要avatar
(它不再在配置文件
对象中)
模板开始查看更改并渲染图像
正确地为什么会这样?这和做一个决定有关系吗
是否在监视功能中从存储中复制
mounted
功能中看到的,我正在设置配置文件
基于getUserProfile
getter的值。这是因为
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函数中使用
同样在mounted函数中,如果this.getUserProfile返回空对象,则根据javascript,空对象总是真实的,直接将对象分配给概要文件不会使对象反应
mounted() {
this.profile = this.getUserProfile ? this.getUserProfile : {}
},
上面的代码可以写成
“阿凡达”道具是否存在于您调用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 = {};
}
}