配置路由

已知,组件名叫做 UserInfo.vue
已知,点击菜单,地址栏的地址变为 /user-info
所以,在 router/index.js 中,配置路由规则:

  1. const routes = [
  2. // 最大级别的规则,对应的组件,会显示在 App.vue 中
  3. // 登录
  4. { path: '/login', component: () => import('@/views/Login.vue') },
  5. // 注册
  6. { path: '/reg', component: () => import('@/views/Reg.vue') },
  7. // 后台主页
  8. {
  9. path: '/',
  10. component: () => import('@/views/Home.vue'),
  11. children: [
  12. { path: 'home', component: () => import('@/views/Chart.vue') },
  13. + { path: 'user-info', component: () => import('@/views/user/UserInfo.vue') }
  14. ]
  15. }
  16. ]

页面布局

<template>
  <el-card class="box-card">
    <div slot="header" class="clearfix">
      <span>更新用户资料</span>
    </div>
    <!-- 内容区放表单 -->
    <el-form label-width="80px">
      <!-- 表单中的每一行,叫做 el-form-item -->
      <el-form-item label="登录账号">
        <el-input></el-input>
      </el-form-item>
      <el-form-item label="用户昵称">
        <el-input></el-input>
      </el-form-item>
      <el-form-item label="用户邮箱">
        <el-input></el-input>
      </el-form-item>
      <el-form-item>
        <el-button type="primary">确认修改</el-button>
        <el-button>取消</el-button>
      </el-form-item>
    </el-form>
  </el-card>
</template>

<script>
export default {}
</script>

<style lang="less" scoped>
.el-card {
  font-size: 13px;
}

.el-form {
  width: 500px;
}
</style>

数据回填

所有的修改操作(不包括修改密码),都需要把原本的数据展示到输入框中,在展示原本数据的基础之上,再去修改。这个过程叫做数据回填。
我们需要的用户数据,在 vuex 中存着呢。
组件中,设置好数据项,值就是vuex中存的数据:

export default {
  data() {
    return {
      userInfo: {
        username: this.$store.state.user.user.username,
        // username: this.$store.state.模块名.数据名,
        nickname: this.$store.state.user.user.nickname,
        email: this.$store.state.user.user.email
      }
    }
  }
}

页面中,使用 v-model 进行双向数据绑定

<el-input v-model="userInfo.username" disabled></el-input>

<el-input v-model="userInfo.nickname"></el-input>

<el-input v-model="userInfo.email"></el-input>

使用对象的浅拷贝简化代码

上述,userInfo 对象中的属性,和 vuex 中的user中的属性完全一致。
那么,代码为什么不能这样写呢?
userInfo: this.$store.state.user.user
因为,对象是引用类型的,上述写法,相当于是 userInfo 和 vuex 中的 user 对象,地址相同了,改一个对象,另一个也会被修改。
解决办法,拷贝一个新的对象:
userInfo: { ...this.$store.state.user.user }
下面是一些实现浅拷贝的方案:

// 对象的浅拷贝
let obj = {
  username: 'zhangsan',
  nickname: '张三',
  email: 'ssss@qq.com'
}

// 浅拷贝:转成JSON字符串,再转回来
// let str = JSON.stringify(obj)
// // console.log(str)
// let obj2 = JSON.parse(str)
// obj2.username = 'lisi'
// console.log(obj, obj2)

// 浅拷贝:使用 Object.assign()
// let obj2 = Object.assign({}, obj)
// obj2.username = 'lisi'
// console.log(obj, obj2)

// 浅拷贝:使用 ... 展开运算符
// let obj2 = { ...obj }
// obj2.username = 'wangwu'
// console.log(obj, obj2)

// 浅拷贝:最原始的 for...in
// let obj2 = {}
// for (let key in obj) {
//   obj2[key] = obj[key]
// }
// obj2.username = 'lisi'
// console.log(obj, obj2)

实现浅拷贝,可以使用上述方案之一。
实现深拷贝,如果自己写的话,就得写递归函数,要不就使用 第三方的方法,参考:https://www.lodashjs.com/docs/lodash.cloneDeep

表单验证

  • 和数据项一致
  • 和验证规则对象同名
  • 和数据项中的一个具体的属性同名

JS代码如下:

export default {
  data() {
    return {
      userInfo: { ...this.$store.state.user.user },
      // 验证规则
      abc: {
        nickname: [
          { required: true, message: '昵称必填', trigger: 'blur' },
          { min: 2, max: 10, message: '昵称长度2~10位', trigger: 'blur' }
        ],
        email: [
          { required: true, message: '邮箱必填', trigger: 'blur' },
          { type: 'email', message: '邮箱格式不正确', trigger: 'blur' }
        ]
      }
    }
  }
}

表单提交,完整的验证

  • 确认修改 按钮,加单击事件 @click="updateUser"
  • 加入 ref="form"

methods 中的 updateUser,完整的验证:

methods: {
  updateUser() {
    // 完整的验证,验证通过,则调用API方法
    this.$refs.form.validate(valid => {
      if (!valid) return
      console.log('验证通过,提交数据')
    })
  }
}

完成修改

封装API方法:

// 更新用户数据
export const updateUserAPI = data => {
  // return request.put('/my/userinfo', 请求体)
  return request.put('/my/userinfo', data)
}

组件中调用方法修改,修改成功,更新 vuex 中的 user数据:

updateUser() {
  // 完整的验证,验证通过,则调用API方法
  this.$refs.form.validate(async valid => {
    if (!valid) return
    // console.log('验证通过,提交数据')
    const { data: res } = await updateUserAPI(this.userInfo)
    if (res.code === 0) {
      this.$message.success(res.message)
      // 更新成功,更新vuex中的 user 数据
      this.$store.dispatch('user/getUser')
    } else {
      this.$message.error(res.message)
    }
  })
}

重置表单

重置按钮,加入单击事件 @click="resetForm"
resetForm方法:

resetForm() {
  // resetFields 恢复表单为最初的样子;去掉红色的表单验证提示
  this.$refs.form.resetFields()
  // 将vuex中的数据,更新到组件中
  this.userInfo = { ...this.$store.state.user.user }
}