当前位置:   article > 正文

黑马头条项目练习(day08)_黑马头条day8

黑马头条day8

今天说到的是个人资料的设置,首先就是准备好我们项目所需要的页面组件

首先是user-profile/index.vue

  1. <template>
  2. <div class="user-profile">
  3. <!-- 导航栏 -->
  4. <van-nav-bar
  5. class="page-nav-bar"
  6. title="个人信息"
  7. left-arrow
  8. @click-left="$router.back()"
  9. />
  10. <!-- /导航栏 -->
  11. <input type="file" hidden ref="file" @change="onChangeFile" />
  12. <!-- 个人信息 -->
  13. <van-cell
  14. class="avatar-cell"
  15. title="头像"
  16. is-link
  17. center
  18. @click="$refs.file.click()"
  19. >
  20. <van-image class="avatar" round fit="cover" :src="user.photo" />
  21. </van-cell>
  22. <van-cell
  23. @click="isUpdateNameShow = true"
  24. title="昵称"
  25. :value="user.name"
  26. is-link
  27. />
  28. <van-cell
  29. @click="isUpdateGenderShow = true"
  30. title="性别"
  31. :value="user.gender === 0 ? '男' : '女'"
  32. is-link
  33. />
  34. <van-cell
  35. @click="isUpdateBirthdayShow = true"
  36. title="生日"
  37. :value="user.birthday"
  38. is-link
  39. />
  40. <!-- /个人信息 -->
  41. <!-- 编辑昵称 -->
  42. <van-popup
  43. v-model="isUpdateNameShow"
  44. style="height: 100%"
  45. position="bottom"
  46. >
  47. <UpdateName
  48. v-model="user.name"
  49. v-if="isUpdateNameShow"
  50. @close="isUpdateNameShow = false"
  51. ></UpdateName>
  52. </van-popup>
  53. <!-- /编辑昵称 -->
  54. <!-- 修改性别 -->
  55. <van-popup
  56. v-model="isUpdateGenderShow"
  57. style="height: 50%"
  58. position="bottom"
  59. >
  60. <UpdateGender
  61. @close="isUpdateGenderShow = false"
  62. v-model="user.gender"
  63. v-if="isUpdateGenderShow"
  64. ></UpdateGender>
  65. </van-popup>
  66. <!-- /修改性别 -->
  67. <!-- 修改生日 -->
  68. <van-popup
  69. v-model="isUpdateBirthdayShow"
  70. style="height: 50%"
  71. position="bottom"
  72. >
  73. <UpdateBirthday
  74. @close="isUpdateBirthdayShow = false"
  75. v-model="user.birthday"
  76. ></UpdateBirthday>
  77. </van-popup>
  78. <!-- /修改生日 -->
  79. <!-- 修改个人头像 -->
  80. <van-popup
  81. v-model="isUpdatePhotoShow"
  82. style="height: 100%"
  83. position="bottom"
  84. >
  85. <updatePhoto :img="img" @close="isUpdatePhotoShow = false" @update-photo="user.photo = $event"></updatePhoto>
  86. </van-popup>
  87. <!-- /修改个人头像 -->
  88. </div>
  89. </template>
  90. <script>
  91. import { getUserProfileAPI } from "@/api";
  92. import UpdateName from "./components/update-name";
  93. import UpdateGender from "./components/update-gender";
  94. import UpdateBirthday from "./components/update-birthday";
  95. import updatePhoto from "./components/update-photo";
  96. export default {
  97. name: "UserProfile",
  98. components: {
  99. UpdateName,
  100. UpdateGender,
  101. UpdateBirthday,
  102. updatePhoto,
  103. },
  104. props: {},
  105. data() {
  106. return {
  107. user: {},
  108. isUpdateNameShow: false,
  109. isUpdateGenderShow: false,
  110. isUpdateBirthdayShow: false,
  111. isUpdatePhotoShow: false,
  112. img: null, // 存储blob地址
  113. };
  114. },
  115. computed: {},
  116. watch: {},
  117. created() {
  118. this.loadUserProfile();
  119. },
  120. mounted() {},
  121. methods: {
  122. async loadUserProfile() {
  123. try {
  124. const { data } = await getUserProfileAPI();
  125. console.log(data);
  126. this.user = data.data;
  127. } catch (error) {
  128. console.log(error);
  129. this.$toast("获取用户信息失败");
  130. }
  131. },
  132. onChangeFile() {
  133. const img = this.$refs.file.files[0];
  134. // 转化blob地址
  135. this.img = window.URL.createObjectURL(img);
  136. // console.log(img_url);
  137. this.isUpdatePhotoShow = true;
  138. // 解决选择上一次相同的图片,不会触发change事件的问题
  139. this.$refs.file.value = "";
  140. },
  141. },
  142. };
  143. </script>
  144. <style scoped lang="less">
  145. .user-profile {
  146. .avatar-cell {
  147. .van-cell__value {
  148. display: flex;
  149. flex-direction: row-reverse;
  150. }
  151. .avatar {
  152. width: 60px;
  153. height: 60px;
  154. }
  155. }
  156. .van-popup {
  157. background-color: #f5f7f9;
  158. }
  159. }
  160. </style>

然后就是user-profile/components/update-name.vue

  1. <template>
  2. <div class="update-name">
  3. <!-- 导航栏 -->
  4. <van-nav-bar
  5. title="设置昵称"
  6. left-text="取消"
  7. right-text="完成"
  8. @click-left="$emit('close')"
  9. @click-right="onComfirm"
  10. />
  11. <!-- /导航栏 -->
  12. <!-- 输入框 -->
  13. <div class="field-wrap">
  14. <van-field
  15. v-model.trim="message"
  16. rows="2"
  17. autosize
  18. type="textarea"
  19. maxlength="11"
  20. placeholder="请输入昵称"
  21. show-word-limit
  22. />
  23. </div>
  24. <!-- /输入框 -->
  25. </div>
  26. </template>
  27. <script>
  28. import { updateUserProfileAPI } from "@/api";
  29. export default {
  30. name: "UpdateName",
  31. components: {},
  32. props: {
  33. value: {
  34. type: String,
  35. required: true,
  36. },
  37. },
  38. data() {
  39. return {
  40. message: this.value,
  41. };
  42. },
  43. computed: {},
  44. watch: {},
  45. created() {},
  46. mounted() {},
  47. methods: {
  48. async onComfirm() {
  49. this.$toast.loading({
  50. message: "更新中...",
  51. forbidClick: true,
  52. duration: 0,
  53. });
  54. const massage = this.message;
  55. if (massage.trim().length === 0) {
  56. return this.$toast("用户名的长度不能为空");
  57. }
  58. try {
  59. // 1. 发送请求实现后台数据的修改
  60. await updateUserProfileAPI({
  61. name: this.message,
  62. });
  63. this.$toast("更新成功");
  64. // 2. 传到父级,更新父级数据
  65. this.$emit("input", massage);
  66. // 3. 关闭弹层
  67. this.$emit("close");
  68. } catch (error) {
  69. console.log(error);
  70. this.$toast("更新失败");
  71. this.$toast("更新用户名失败");
  72. }
  73. },
  74. },
  75. };
  76. </script>
  77. <style scoped lang="less">
  78. .field-wrap {
  79. padding: 20px;
  80. }
  81. </style>

然后就是user-profile/components/update-gender.vue

  1. <template>
  2. <div class="update-gender">
  3. <van-picker
  4. @cancel="$emit('close')"
  5. title="设置性别"
  6. show-toolbar
  7. :columns="columns"
  8. :default-index="value"
  9. @change="onChange"
  10. @confirm="onConfirm"
  11. />
  12. </div>
  13. </template>
  14. <script>
  15. import { updateUserProfileAPI } from "@/api";
  16. export default {
  17. name: "",
  18. components: {},
  19. props: {
  20. value: {
  21. type: Number,
  22. required: true,
  23. },
  24. },
  25. data() {
  26. return {
  27. columns: ["男", "女"],
  28. localGender: 0,
  29. };
  30. },
  31. computed: {},
  32. watch: {},
  33. created() {},
  34. mounted() {},
  35. methods: {
  36. onChange(picker, value, index) {
  37. // this.$toast(`当前值:${value}, 当前索引:${index}`);
  38. this.localGender = index;
  39. },
  40. async onConfirm() {
  41. this.$toast.loading({
  42. message: "更新中...",
  43. forbidClick: true,
  44. duration: 0,
  45. });
  46. const localGender = this.localGender;
  47. try {
  48. // 1. 发送请求实现后台数据的修改
  49. await updateUserProfileAPI({
  50. gender: this.localGender,
  51. });
  52. this.$toast("更新成功");
  53. // 2. 传到父级,更新父级数据
  54. this.$emit("input", localGender);
  55. // 3. 关闭弹层
  56. this.$emit("close");
  57. } catch (error) {
  58. console.log(error);
  59. this.$toast("更新失败");
  60. this.$toast("更新用户名失败");
  61. }
  62. },
  63. },
  64. };
  65. </script>
  66. <style lang="less" scoped></style>

然后就是user-profile/components/update-birthday.vue

  1. <template>
  2. <div class="update-birthday">
  3. <van-datetime-picker
  4. v-model="currentDate"
  5. type="date"
  6. title="选择年月日"
  7. :min-date="minDate"
  8. :max-date="maxDate"
  9. @cancel="$emit('close')"
  10. @confirm="onConfirm"
  11. />
  12. </div>
  13. </template>
  14. <script>
  15. import { updateUserProfileAPI } from "@/api";
  16. import dayjs from "dayjs";
  17. export default {
  18. name: "UpdateBirthday",
  19. components: {},
  20. props: {
  21. value: {
  22. type: String,
  23. required: true,
  24. },
  25. },
  26. data() {
  27. return {
  28. minDate: new Date(1900, 0, 1),
  29. // maxDate: new Date(2025, 10, 1),
  30. maxDate: new Date(),
  31. currentDate: new Date(this.value),
  32. };
  33. },
  34. computed: {},
  35. watch: {},
  36. created() {},
  37. mounted() {},
  38. methods: {
  39. async onConfirm() {
  40. this.$toast.loading({
  41. message: "更新中...",
  42. forbidClick: true,
  43. duration: 0,
  44. });
  45. const localBirthday = dayjs(this.currentDate).format("YYYY-MM-DD");
  46. try {
  47. // 1. 发送请求实现后台数据的修改
  48. await updateUserProfileAPI({
  49. birthday: localBirthday,
  50. });
  51. this.$toast("更新成功");
  52. // 2. 传到父级,更新父级数据
  53. this.$emit("input", localBirthday);
  54. // 3. 关闭弹层
  55. this.$emit("close");
  56. } catch (error) {
  57. console.log(error);
  58. this.$toast("更新失败");
  59. this.$toast("更新用户名失败");
  60. }
  61. },
  62. },
  63. };
  64. </script>
  65. <style lang="less" scoped></style>

然后就是user-profile/components/update-photo.vue

  1. <template>
  2. <div class="update-photo">
  3. <img class="img" :src="img" ref="img" />
  4. <div class="toolbar">
  5. <div class="cancel" @click="$emit('close')">取消</div>
  6. <div class="confirm" @click="onConfirm">完成</div>
  7. </div>
  8. </div>
  9. </template>
  10. <script>
  11. import { updateUserPhotoAPI } from "@/api";
  12. import "cropperjs/dist/cropper.css";
  13. import Cropper from "cropperjs";
  14. export default {
  15. name: "UpdatePhoto",
  16. components: {},
  17. props: {
  18. // 预览图片地址信息
  19. img: {
  20. type: [String, Object],
  21. required: true,
  22. },
  23. },
  24. data() {
  25. return {
  26. cropper: null,
  27. };
  28. },
  29. computed: {},
  30. watch: {},
  31. created() {},
  32. mounted() {
  33. const image = this.$refs.img;
  34. this.cropper = new Cropper(image, {
  35. viewMode: 1,
  36. dragMode: "move",
  37. aspectRatio: 1,
  38. // autoCropArea: 1,
  39. cropBoxMovable: false,
  40. cropBoxResizable: false,
  41. background: false,
  42. });
  43. },
  44. methods: {
  45. // 确定事件
  46. async onUpdatePhoto(blob) {
  47. this.$toast.loading({
  48. message: "更新中...",
  49. forbidClick: true,
  50. duration: 0,
  51. });
  52. const formData = new FormData();
  53. formData.append("photo", blob);
  54. try {
  55. // 1. 发送请求实现后台数据的修改
  56. const { data } = await updateUserPhotoAPI(formData);
  57. console.log(data);
  58. this.$toast("更新成功");
  59. // 2. 传到父级,更新父级数据
  60. this.$emit("update-photo", data.data.photo);
  61. // 3. 关闭弹层
  62. this.$emit("close");
  63. } catch (error) {
  64. console.log(error);
  65. this.$toast("更新失败");
  66. this.$toast("更新头像失败");
  67. }
  68. },
  69. onConfirm() {
  70. this.cropper.getCroppedCanvas().toBlob(
  71. (blob) => {
  72. console.log(blob);
  73. this.onUpdatePhoto(blob);
  74. // const formData = new FormData();
  75. // Pass the image file name as the third parameter if necessary.
  76. // formData.append("croppedImage", blob /*, 'example.png' */);
  77. // Use `jQuery.ajax` method for example
  78. // $.ajax("/path/to/upload", {
  79. // method: "POST",
  80. // data: formData,
  81. // processData: false,
  82. // contentType: false,
  83. // success() {
  84. // console.log("Upload success");
  85. // },
  86. // error() {
  87. // console.log("Upload error");
  88. // },
  89. // });
  90. } /*, 'image/png' */
  91. );
  92. },
  93. },
  94. };
  95. </script>
  96. <style scoped lang="less">
  97. .update-photo {
  98. background-color: #000;
  99. height: 100%;
  100. .toolbar {
  101. position: fixed;
  102. left: 0;
  103. right: 0;
  104. bottom: 0;
  105. display: flex;
  106. justify-content: space-between;
  107. .cancel,
  108. .confirm {
  109. width: 90px;
  110. height: 90px;
  111. font-size: 30px;
  112. display: flex;
  113. justify-content: center;
  114. align-items: center;
  115. color: #fff;
  116. }
  117. }
  118. }
  119. .img {
  120. display: block;
  121. max-width: 100%;
  122. }
  123. </style>

over!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小桥流水78/article/detail/988039
推荐阅读
相关标签
  

闽ICP备14008679号