目录

1.项目准备

技术栈:

  1. Vue
  2. vue-router
  3. vant
  4. axios,抽取api
  5. vue-cli脚手架
  6. Vuex状态管理

1.1 rem适配

头条项目使用rem适配

需求:浏览器尺寸改变之后,页面元素自动适配

步骤

下包导包

npm i amfe-flexible

main.js导入

通过modele的对应模块可以分隔屏幕

在对应文件可以设置根文字的大小

1.2 通用样式CSS

  1. 存放目录在 /src/styles/base.less

  1. main.js中导入样式,顺序应在组件库之后,自己写的要覆盖其他的,在后面引入

1.3删除测试代码

在创建项目的时候会自动创建一些测试代码

针对删除

  1. App.vue内容干掉

    1. 保留挂载点 #app 和 router-view渲染结构
  2. views目录内容,清空多余的组件,创建需要的组件
  3. /router/index.js
    1. 自定义路由规则
  4. components/HelloWorld.vue删掉

1.4Git托管

https 或 ssh托管

webstorm一键链接和管理

2.login页面

2.1 页面布局和表单校验

布局

​ 1.导航栏

​ 2.表单

​ 3.提交按钮

校验

​ 1.添加rule对象规则

​ required必填项和提示信息

​ 正则表达式规定输入信息格式

vant-field组件

vant-form组件

  1. van-form

    1. @submit:表单验证成功之后触发的回调函数

      1. 参数是一个对象
      2. 内部的输入元素的name属性和value值,拼接为一个对象
  2. 输入元素
    1. rules:校验规则

      1. 数组
      2. 每一条规则是一个对象
      3. required:必填
      4. message:提示信息
      5. pattern:正则的规则
  1. <template>
  2. <div class="login-container">
  3. <!-- 导航栏 -->
  4. <van-nav-bar title="登录" class="my-nav-bar" />
  5. <!-- 表单 -->
  6. // 内置的submit事件调用method的onSubmit自定义方法
  7. <van-form @submit="onSubmit">
  8. <van-field
  9. v-model="username"
  10. //name提交的参数名
  11. //valueinput框由用户输入
  12. name="用户名"
  13. label="手机号"
  14. //必填项
  15. required
  16. placeholder="请输入手机号"
  17. :rules="[
  18. //校验规则
  19. { required: true, message: '请输入手机号' },
  20. {
  21. pattern: /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/,
  22. message: '手机号格式不对'
  23. }
  24. ]"
  25. />
  26. <van-field
  27. v-model="password"
  28. name="密码"
  29. label="验证码"
  30. required
  31. placeholder="请输入验证码"
  32. :rules="[
  33. { required: true, message: '请填写验证码' },
  34. { pattern: /\d{6}/, message: '验证码格式不对' }
  35. ]"
  36. />
  37. <div style="margin: 16px;">
  38. <van-button round block type="info" native-type="submit"
  39. >提交</van-button
  40. >
  41. </div>
  42. </van-form>
  43. </div>
  44. </template>
  45. <script>
  46. export default {
  47. //组件暴露的名称
  48. name: 'login',
  49. //login组件的数据,以函数形式表达
  50. data () {
  51. return {
  52. username: '',
  53. password: ''
  54. }
  55. },
  56. //对应表单的自定义方法
  57. methods: {
  58. //values是一个对象,name(代码定义)-value(用户输入)
  59. onSubmit (values) {
  60. console.log('submit', values)
  61. }
  62. }
  63. }
  64. </script>
  65. <style lang="less">
  66. //设置登录条的样式
  67. .login-container {
  68. .my-nav-bar {
  69. background-color: #3196fa;
  70. .van-nav-bar__title {
  71. color: white;
  72. }
  73. }
  74. }
  75. </style>

2.2login页的接口抽取

下包导包

  1. 下包:npm i axios

  2. 导入在/src/api/login.js

  3. create方法创建一个副本

4.可用信息

  1. 手机号很多个
  2. mobile:13912345678
  3. 验证码固定的
  4. code:246810

2.5.loading效果

避免用户频繁提交,为按钮增加loading效果,并且切换启用禁用状态

需求:

  1. 数据提交时,为按钮增加loading效果
  2. 切换启用/禁用状态,避免重复点击
  3. 通过button按钮的属性实现

Example

  1. <template>
  2. <div>
  3. <button @click="isLoading = !isLoading">切换loading</button>
  4. <br />
  5. <van-button :loading="isLoading" type="primary" />
  6. <br />
  7. <van-button :loading="isLoading" type="primary" loading-type="spinner" />
  8. <br />
  9. <van-button
  10. //当加载中的时候,禁止提交按钮的点击,其状态为true是禁止
  11. :disabled="isLoading"
  12. //当加载中的时候,其状态时true,显示加载动画
  13. :loading="isLoading"
  14. //type =info,是信息按钮,为蓝色
  15. type="info"
  16. //加载中的文字
  17. loading-text="加载中..."
  18. >按钮</van-button
  19. >
  20. </div>
  21. </template>
  22. <script>
  23. export default {
  24. data () {
  25. return {
  26. isLoading: false
  27. }
  28. }
  29. }
  30. </script>
  31. <style></style>

2.6封装token方法

实现功能,把token保存到缓存中

步骤:

  1. sessionStorage刷新不在了
  2. localStorage刷新还在
  3. .then
    1. 保存起来

      1. 默认无法直接保存复杂类型
      2. 除非转为JSON格式的字符串
      3. JSON.stringify(复杂类型)-->字符串

token在多个地方都需要使用,比如登出,接口我们把它抽取一下,方便调用,同时避免出错,为了方便操作缓存,封装工具函数

  1. /src/utils/token.js

  1. 提供3个方法并暴露出来

    1. saveToken

      1. 保存token
      2. 接收参数
    2. removeToken
      1. 删除token
      2. 无参数,无返回至
    3. getToken
      1. 返回token

实现token工具函数的封装

  1. // 定义key
  2. const TOKENKEY = 'top-line-token'
  3. // 保存 token
  4. const saveToken = tokenObj => {
  5. window.localStorage.setItem(TOKENKEY, JSON.stringify(tokenObj))
  6. }
  7. // 删除 token
  8. const removeToken = () => {
  9. window.localStorage.removeItem(TOKENKEY)
  10. }
  11. // 获取 token
  12. const getToken = () => {
  13. //getToken需要return
  14. // str-->obj
  15. return JSON.parse(window.localStorage.getItem(TOKENKEY))
  16. }
  17. //将定义的方法暴露出去
  18. export { saveToken, removeToken, getToken }

2.7轻提示toast

在调用onsumit方法提交成功之后要打印数

目录

据和弹出轻提示

1.导入请求方法

2.在点击提交按钮时调用onsumit方法,提交请求之后通过then和catch判断是否请求成功

3.如果请求成功就弹出轻提示--陈工

4.如果请求失败就弹出轻提示--失败

2.8整合三部分代码

loading-MV代码、token工具函数封装、、toast-MV代码、

1.在请求成功时除了改变toast的轻提示,还有改变loading动画的状态

2.在请求时时除了改变toast的轻提示,还有改变loading动画的状态

3.为了防止loading响应太快,出现闪顿,设置一个定时器给关闭loading的语句

4.在Model结构中控制改变 过渡动画的状态 以及 禁用的状态

实现代码如下

  1. <template>
  2. <div class = "login-container">
  3. <!-- 导航栏 -->
  4. <van-nav-bar title = "登录" class = "my-nav-bar"/>
  5. <!-- 表单 -->
  6. <van-form @submit = "onSubmit">
  7. <van-field
  8. //绑定data中的mobile数据
  9. v-model = "mobile"
  10. //设置请求的键名
  11. name = "mobile"
  12. //绑定要显示的文字
  13. label = "手机号"
  14. //设置必选项
  15. required
  16. //设置占位符placeholder,同时给占位符文本内容
  17. placeholder = "请输入手机号"
  18. //对文本框的内容通过正则进行限制
  19. :rules = "[
  20. { required: true, message: '请输入手机号' },
  21. {
  22. pattern: /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/,
  23. message: '手机号格式不对'
  24. }
  25. ]"
  26. />
  27. <van-field
  28. v-model = "code"
  29. name = "code"
  30. label = "验证码"
  31. required
  32. placeholder = "请输入验证码"
  33. //对文本框的内容通过正则进行限制
  34. :rules = "[
  35. { required: true, message: '请填写验证码' },
  36. { pattern: /\d{6}/, message: '验证码格式不对' }
  37. ]"
  38. />
  39. <div style = "margin: 16px;">
  40. <van-button
  41. :loading = "isLoading"
  42. :disabled = "isLoading"
  43. loading-text = "登录ing"
  44. round
  45. block
  46. type = "info"
  47. native-type = "submit"
  48. >提交
  49. </van-button
  50. >
  51. </div>
  52. </van-form>
  53. </div>
  54. </template>
  55. <script>
  56. // 导入api的请求方法
  57. import { userLogin } from '../../api/login'
  58. // 导入 token工具函数
  59. import { saveToken } from '../../utils/token'
  60. export default {
  61. name: 'login',
  62. data () {
  63. return {
  64. // 在页面进入的时候加载一个手机号和验证吗,方便测试。
  65. // 逻辑上说,应该由用户输入和验证
  66. mobile: '13912345678', // 手机号
  67. code: '246810', // 验证码
  68. isLoading: false// 是否正在加载中
  69. }
  70. },
  71. methods: {
  72. onSubmit (values) {
  73. //键名是name,键值是用户在表单输入的,为了方便测试设置了一个默认的值
  74. // values是一个对象{mobile:'xxx',code:'xxx'}
  75. // 开启loading
  76. this.isLoading = true
  77. //userlogin是封装的请求方法,传入请求的对象{ mobile: '13912345678', code: '246810' }
  78. userLogin(values)
  79. .then(res => {
  80. console.log('res:', res)
  81. // 保存token
  82. saveToken(res.data.data)
  83. //设置定时器的目的是为了在呈现效果的时候不会闪顿,更加可控和顺滑
  84. //请求成功之后关闭轻提示,关闭动画
  85. setTimeout(() => {
  86. this.$toast.success('登录成功!')
  87. this.isLoading = false
  88. }, 500)
  89. })
  90. .catch(errRes => {
  91. console.log('errRes:', errRes)
  92. //设置定时器的目的是为了在呈现效果的时候不会闪顿,更加可控和顺滑
  93. //请求失败之后关闭轻提示,关闭动画
  94. setTimeout(() => {
  95. this.$toast.fail('登录失败!')
  96. this.isLoading = false
  97. }, 500)
  98. })
  99. }
  100. }
  101. }
  102. </script>
  103. //设置导航栏nav的样式
  104. <style lang = "less">
  105. .login-container {
  106. .my-nav-bar {
  107. background-color: #3196fa;
  108. .van-nav-bar__title {
  109. color: white;
  110. }
  111. }
  112. }
  113. </style>

2.9使用token的保存方法

2.10跳转到home

  1. userLogin(values).then(res => {
  2. /* 进入到then就表示已经成功请求到了 */
  3. console.log('res', res)
  4. saveToken(res.data.data)
  5. /* 防止太快看不到loading动画,设一个定时器 */
  6. setTimeout(() => {
  7. this.$toast.success('登录成功!')
  8. this.isLoading = false
  9. this.$router.push({
  10. path: '/home'
  11. })
  12. }, 300)

2.11 重定向

在没有输入url时,打开项目看到的是白色界面,最后咱们通过重定向来解决这个问题 '/'跳转到home

  1. routes: [
  2. {
  3. // 默认地址
  4. path: '/a',
  5. // 重定向的地址 需要被注册
  6. redirect: '/b'
  7. }
  8. ]

3.layout页面

3.1整合底部layout结构

  1. <template>
  2. <div class = "layout-container">
  3. layout
  4. <van-tabbar v-model = "active" route>
  5. //根据样式找到对应的图标类名
  6. <van-tabbar-item icon = "home-o">首页</van-tabbar-item>
  7. <van-tabbar-item icon = "chat-o">问答</van-tabbar-item>
  8. <van-tabbar-item icon = "video-o">视频</van-tabbar-item>
  9. <van-tabbar-item icon = "user-o">我的</van-tabbar-item>
  10. </van-tabbar>
  11. </div>
  12. </template>
  13. <script>
  14. export default {
  15. name: 'layout',
  16. data () {
  17. return {
  18. //高亮第一个图标
  19. active: 0
  20. }
  21. }
  22. }
  23. </script>
  24. <style></style>

<van-tabbar v-model = "active" route> route的作用是开启路由模式,vant的Tabbar组件的参数

3.2layout嵌套路由

1.文件结构

2.路由导入

  1. import home from '../views/layout/home'
  2. import question from '../views/layout/question'
  3. import movie from '../views/layout/movie'
  4. import user from '../views/layout/user'

3.渲染结构的出口在layout的index.vue中的vue-router

  1. <!--嵌套路由的出口-->
  2. <router-view></router-view>

4.嵌套路由出口的渲染(router-view)

5.children在定义的时候也决定了它的路由出口在父组件上,所以组件的router-view最终渲染的位置在layout组件上,通过chrome插件可以查看 children: [{},{},{}]

4.user页面

4.1.整合路由

SSR直连,解决timeout

4.2顶部区域

  1. <template>
  2. <div class = "user-container">
  3. <div class = "info-box">
  4. <van-image
  5. class = "my-image"
  6. round
  7. src = "https://img01.yzcdn.cn/vant/cat.jpeg"
  8. />
  9. <h2 class = "name">
  10. 起飞
  11. <br>
  12. <van-tag color = "#fff" text-color = "#3296fa" type = "primary">2021-6-10</van-tag>
  13. </h2>
  14. </div>
  15. </div>
  16. </template>
  17. <script>
  18. export default {
  19. name: 'user'
  20. }
  21. </script>
  22. <style lang = "less">
  23. .user-container {
  24. .info-box {
  25. height: 100px;
  26. background-color: #3296fa;
  27. display: flex;
  28. padding-left: 18px;
  29. // 从 弹性布局 左边开始
  30. justify-content: flex-start;
  31. align-items: center;
  32. .my-image {
  33. width: 60px;
  34. height: 60px;
  35. margin-right: 5px;
  36. }
  37. .name {
  38. margin-left: 5px;
  39. color: white;
  40. font-size: 15px;
  41. font-weight: normal;
  42. }
  43. }
  44. }
  45. </style>

拓--justify-content:的样式展示

justify-content:flex-start

4.3操作按钮

less语法有&操作符 用法:&符号有2中用法,其一:父选择符;其二:且的意思,在这里使用的

设置操作链接的布局和样式

实现结构

  1. <van-row class = "my-control-box">
  2. <van-col class = "my-col" span = "8"
  3. >
  4. <van-icon class = "my-icon my" name = "newspaper-o"/>
  5. 我的作品
  6. </van-col
  7. >
  8. <van-col class = "my-col " span = "8"
  9. >
  10. <van-icon class = "my-icon star" name = "star-o"/>
  11. 我的收藏
  12. </van-col
  13. >
  14. <van-col class = "my-col " span = "8"
  15. >
  16. <van-icon class = "my-icon history" name = "tosend"/>
  17. 阅读历史
  18. </van-col
  19. >
  20. </van-row>

实现样式

  1. //设置每一列的字体大小,并且居中
  2. .my-col {
  3. font-size: 12px;
  4. text-align: center;
  5. }
  6. //单独给icon字体图标设置大小,并且转为块级元素
  7. .my-icon {
  8. font-size: 28px;
  9. display: block;
  10. //且的意思,my-icon且my
  11. &.my {
  12. color: #77aaff;
  13. }
  14. &.star {
  15. color: #ff0000;
  16. }
  17. &.history {
  18. color: #ffaa00;
  19. }
  20. }
  21. }

4.4底部区域

1.icon:左侧图标

2.title:左侧文本

3.is-link:右侧箭头

实现结构

  1. <template>
  2. <div>
  3. <van-cell-group>
  4. <van-cell title="编辑资料" icon="edit" is-link />
  5. <van-cell title="小智同学" icon="chat-o" is-link />
  6. <van-cell title="系统设置" icon="setting-o" is-link />
  7. <van-cell title="退出登录" icon="warning-o" is-link />
  8. </van-cell-group>
  9. </div>
  10. </template>
  11. <script>
  12. export default {}
  13. </script>
  14. <style></style>

实现样式

  1. .my-control-box {
  2. //设置上下内边距,把三个小图标挤进去
  3. padding-top: 20px;
  4. padding-bottom: 20px;
  5. //设置每一列的字体大小,并且居中
  6. .my-col {
  7. font-size: 12px;
  8. text-align: center;
  9. }
  10. //单独给icon字体图标设置大小,并且转为块级元素
  11. .my-icon {
  12. font-size: 28px;
  13. display: block;
  14. //且的意思,my-icon且my
  15. &.my {
  16. color: #77aaff;
  17. }
  18. &.star {
  19. color: #ff0000;
  20. }
  21. &.history {
  22. color: #ffaa00;
  23. }
  24. }
  25. }

4.5用户信息

1.测试接口

2.api抽取

在src/api文件夹封装一个user.js用来保存user页面用到的api

  1. //导入请求组件axios
  2. import axios from 'axios'
  3. // 导入获取token的工具函数
  4. import { getToken } from '@/utils/token'
  5. //设置基地址
  6. const request = axios.create({
  7. baseURL: 'http://toutiao-app.itheima.net'
  8. })
  9. //封装获取用户信息的方法
  10. const getUserInfo = () => {
  11. return request({
  12. //剩余的请求地址
  13. url: '/v1_0/user/profile',
  14. //请求的方式
  15. method: 'get',
  16. //请求头的设置
  17. headers: {
  18. Authorization: `Bearer ${getToken().token}`
  19. }
  20. })
  21. }
  22. //暴露获取用户信息的方法
  23. export { getUserInfo }
  24. //保存的token
  25. //{token: "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2M…HNlfQ.4XdqWBCJ-Q_IGxNY5jEekiqrmzOg6zZIYLQkbK5WIWE", refresh_token: "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2M…ydWV9.UycupnAiENN4AZROq7n8LbxkNEAuUYZHcXe52SFfVgs"}
  26. ////获得请求头的授权token,通过调用token工具函数,因为在saveToken的时候是一个对象,所以调用函数得到的是一个对象 setItem(TOKENKEY, JSON.stringify(tokenObj))

3.使用添加数据

实现逻辑

  1. //导入默认的图片
  2. import defaultImg from '../../../assets/logo.png'
  3. // 导入 请求的 api方法
  4. import { getUserInfo } from '../../../../src/api/user'
  5. //暴露接口
  6. export default {
  7. name: 'user',
  8. data () {
  9. return {
  10. defaultImg,
  11. // 设置一个空对象保存用户信息
  12. userInfo: {}
  13. }
  14. },
  15. created () {
  16. // 在钩子添加请求到的信息
  17. getUserInfo().then(res => {
  18. console.log('res:', res)
  19. //如果获取成功用户信息,添加到 userInfo: {}
  20. this.userInfo = res.data.data
  21. })
  22. }
  23. }

实现结构

  1. <div class = "info-box">
  2. <van-image
  3. class = "my-image"
  4. round
  5. //设置返回数据的头像
  6. :src = "userInfo.photo"
  7. />
  8. <h2 class = "name">
  9. //设置返回数据的名称
  10. {{ userInfo.name }}
  11. <br>
  12. //设置返回数据的生日
  13. <van-tag color = "#fff" text-color = "#3296fa" type = "primary"> {{ userInfo.birthday }}</van-tag>
  14. </h2>
  15. </div>

4.6登出功能

通过dialog模态框实现弹出

清空信息的语句在后面有改善,通过Vuex在登出方法中做出优化

  1. this.$store.commit('setUserInfo', {})

实现逻辑

  1. methods: {
  2. logout () {
  3. //
  4. this.$dialog
  5. .confirm({})
  6. .then(() => {
  7. // 登出后删除token数据
  8. removeToken()
  9. // 登出后将用户信息清空,之前保存的用户信息是一个对象
  10. this.userInfo = {}
  11. // 登出后通过router组件跳转页面到home,因为不是后台管理系统所以不需要跳转到login登录页面
  12. this.$router.push({
  13. path: '/home'
  14. })
  15. // 登出失败返回一个catch
  16. }).catch(() => {
  17. console.log('catch')
  18. })
  19. }
  20. }

实现功能

在登出的标签注册一个点击事件

  1. <van-cell title = "退出登录" icon = "warning-o" is-link @click = "logout"/>

4.7登录判断token--前置守卫

限制在user页面进行判断,其他页面不登陆也可以访问

文件目录 --src/router/index.js

实现逻辑

导航守卫的三个参数必须按顺序书写

  1. //routes参数的设置
  2. {
  3. path: 'user',
  4. name: 'user',
  5. component: user,
  6. meta: {
  7. //自定义的规则字段
  8. needLogin: true
  9. }
  10. }
  11. // 1.在导航守卫中先获取meta是否需要登录
  12. router.beforeEach((to, from, next) => {
  13. //判断是否需要
  14. if (to.meta.needLogin !== true) {
  15. //如果不需要元信息,直接返回next()
  16. return next()
  17. }
  18. // 拿到令牌
  19. const tokenObj = getToken()
  20. //2.判断token令牌是否存在
  21. if (tokenObj === null) {
  22. //如果令牌为空,弹出轻提示
  23. Toast.fail('请先登录')
  24. //如果令牌为空,跳转到login页面
  25. return next({ path: '/login' })
  26. }
  27. //token既不是空,而且需要元信息
  28. next()
  29. //3.判断token令牌是否正确
  30. // 拿到个人的信息
  31. //getUserInfo根据已有的token发起请求,并且返回用户的数据
  32. getUserInfo()
  33. // 请求成功之后携带数据直接到下一站
  34. .then(res => {
  35. console.log(res)
  36. next()
  37. })
  38. // 请求失败,根据返回的状态码401判断token不正确(后端完成)
  39. .catch(errRes => {
  40. if (errRes.response.status === 401) {
  41. removeToken()
  42. // 如果token给出提示请先登录
  43. Toast.fail('请先登录')
  44. // 如果token不对跳转登录页面
  45. next({ path: '/login' })
  46. }
  47. })
  48. })

console.dir()可以解析属性的值

解决Vuerouter的Promise报错(吞掉)

  1. // 吞掉 没有处理的 promise的错误
  2. const originalPush = VueRouter.prototype.push
  3. VueRouter.prototype.push = function push (location, onResolve, onReject) {
  4. if (onResolve || onReject) {
  5. // 执行之后 阻断后续代码
  6. return originalPush.call(this, location, onResolve, onReject)
  7. }
  8. return originalPush.call(this, location).catch(err => err)
  9. }

4.8 共享用户信息-vuex

1.添加vuex组件

vue add vuex

在mian.js文件上

  1. // 将Vuex仓库注册Vue构造函数上
  2. store,

2.修改用户信息

src/router/index.js

  1. // 将获取的用户信息共享到Vuex的仓库的state中,通过定义的 mutations的setUserInfo方法修改预设置的信息信息
  2. //第一个参数是调用的修改数据的方法,第二个数据是修改后的数据
  3. store.commit('setUserInfo', res.data.data)

3.设置路由元信息

  1. export default new Vuex.Store({
  2. //设置原始数据
  3. state: {
  4. userInfo: {}
  5. },
  6. mutations: {
  7. //定义修改数据的方法
  8. //这个方法接收一个原始的数据,第二个参数是传入的修改后的数据
  9. setUserInfo (state, newUserInfo) {
  10. state.userInfo = newUserInfo
  11. }
  12. },

4.查看共享的数据

4.9用户页面调整

1.导航守卫中请求了一次

导航守卫属于router,在router文件夹的index.js当中

​ 目的有三

​ 为了判断是否需要判断needLogin

​ 为了判断请求的数据是否存在token

​ 为了判断token的值是否正确,401?

这里拿到了用户的数据只进行了判断,没有进行使用

2.加载user页面请求一次

这里通过调用 getUserInfo()方法获取,用来渲染页面。

请求用户信息的方法getUserInfo()定义在src/api/user中,因为也算是请求,放在api文件当中

3.解决多次请求

Vuex本质是共享数据,统一放在新建的src/store的文件中的index.js

用户信息保存到Vuex中,调整用户页面信息的数据来源(目的是为了只请求一次放在仓库中,减少请求次数),之前是两次里请求

在登出方法logout(),修改清空数据的语句

  1. // 登出后将用户信息清空,之前保存的用户信息是一个对象
  2. // this.userInfo = {}
  3. // 优化登出信息清空,现在拿到的信息是从Vuex中来的
  4. this.$store.commit('setUserInfo', {})

4.10登陆成功返回访问页

1.正常访问login页面之后区home页面

2.因为没有登录被转到login,在登录成功之后要返回

​ 1.login/index.vue登陆成功之后进行判断

​ 1.有redirect参数

​ 2.没有redirect参数

实现逻辑

在router文件的index.js中实现redirect参数的携带

1.没有token携带redirect参数

  1. if (tokenObj === null) {
  2. Toast.fail('请先登录')
  3. // 如果没有token令牌跳转到登陆页面,并且携带redirect参数
  4. return next({
  5. path: '/login',
  6. // 定义重新定向的到哪去的路径参数,这个路径参数指向当前没登陆的页面
  7. query: { redirect: to.path }
  8. })
  9. }

2.token令牌错误携带redirect参数

  1. .catch(errRes => {
  2. if (errRes.response.status === 401) {
  3. removeToken()
  4. // 如果token给出提示请先登录
  5. Toast.fail('请先登录')
  6. // 如果token不对跳转登录页面
  7. next({
  8. path: '/login',
  9. // 如果请求的token令牌是错误的也要重新定向
  10. query: { redirect: to.path }
  11. })
  12. }
  13. })

3.在login文件中的index.vue对redirect参数进行判断

该逻辑写在表单提交成功的then之中

  1. const redirect = this.$route.query.redirect
  2. if (redirect) {
  3. return this.$router.push({
  4. path: redirect
  5. })
  6. }
  7. // 没有redirect参数
  8. this.$router.push({
  9. path: '/home'
  10. })

5.edit页面

5.1整合路由

1.创建edit页面在src/views/layout/edit/index.vue

  1. <template>
  2. <div class = "edit-container">
  3. <!-- 导航条 -->
  4. <van-nav-bar left-arrow title = "编辑资料"></van-nav-bar>
  5. <!-- 头像部分 -->
  6. <div class = "avatar">
  7. <van-image fit = "cover" round src = "https://img.yzcdn.cn/vant/cat.jpeg"/>
  8. </div>
  9. <!-- 信息展示 -->
  10. <van-cell-group>
  11. <van-cell is-link title = "名称" value = "昵称"/>
  12. <van-cell is-link title = "性别" value = "男"/>
  13. <van-cell is-link title = "生日" value = "2020-1-1"/>
  14. </van-cell-group>
  15. </div>
  16. </template>
  17. <script>
  18. export default {
  19. name: 'editUser'
  20. }
  21. </script>
  22. <style lang = "less">
  23. .edit-container {
  24. // 导航条部分
  25. .van-nav-bar {
  26. background-color: #3196fa;
  27. .van-nav-bar__title {
  28. color: #fff;
  29. }
  30. .van-icon-arrow-left {
  31. color: #fff;
  32. }
  33. }
  34. // 头像部分
  35. .avatar {
  36. padding: 20px 0;
  37. text-align: center;
  38. .van-image {
  39. width: 120px;
  40. height: 120px;
  41. }
  42. }
  43. }
  44. </style>

2.在src/router/index.js创建对应的edit路由

路由安放的位置在layout路由的children序列当中

layout是所有chidren路由渲染的出口<router-view></router-view>

  1. {
  2. path: 'edit',
  3. name: 'edit',
  4. component: edit
  5. },

5.2user跳转edit

1.添加跳转属性

操作目录:src/views/layout/user/index.vue

  1. <van-cell title = "编辑资料" icon = "edit" is-link to = "/edit"/>

2.从edit返回user的两种方法

操作目录src/views/layout/edit/index.vue

go方法

  1. onClickleft () {
  2. this.$router.go(-1)
  3. }

back方法

  1. onClickleft () {
  2. this.$router.back()
  3. }

5.3 edit登录判断

需求:

  1. 编辑页面需要登录才可以访问

步骤:

  1. 给任意希望登录才可以访问的路由(页面)
  2. 添加元信息即可
    1. meta:{needLogin:true}

5.4编辑隐藏Tabbar

需求:

  1. 访问/edit页面时隐藏tabbar
  2. 结合路由元信息实现

步骤:

  1. 配置路由元信息 ,src/router/index.js
  1. {
  2. path: 'edit',
  3. name: 'edit',
  4. component: edit,
  5. meta: {
  6. needLogin: true,
  7. // 给他设置单独的路由元,为false,其他没有true默认显示,在V-show取反时直接v-show:false隐藏
  8. hideTabbar: true
  9. }
  10. }

2.在layout页面隐藏底部导航条,src/views/layout/index.vue

​ 获取元路由信息

​ 对预设的hideTabbar取反

  1. <van-tabbar v-model = "active" route v-show = "!$route.meta.showTabbar">

3.不隐藏的效果:

4.隐藏的实现效果:

5.5渲染edit页面

需求:

  1. 进入编辑页面,把用户数据渲染到页面上

步骤:

  1. 路由中对token进行了判断,并且将数据保存到了Vuex的仓库当中 store.commit('setUserInfo', res.data.data)

  2. 在edit页面获取仓库中的数据

    ​ 在计算属性中定义一个用户信息的方法,并且返回用户的信息

    1. computed: {
    2. // 在计算属性内部定义一个方法,调用时不需要加括号
    3. userInfo () {
    4. return this.$store.state.userInfo
    5. }

3.将获得数据添加到页面, src/views/layout/edit/index.vue

  1. <div class = "avatar">
  2. <van-image fit = "cover" round :src = "userInfo.photo"/>
  3. </div>
  4. <!-- 信息展示 -->
  5. <van-cell-group>
  6. <van-cell is-link title = "名称" :value = "userInfo.name"/>
  7. <van-cell is-link title = "性别" :value = "userInfo.gender === 0?'男':'女'"/>
  8. <van-cell is-link title = "生日" :value = "userInfo.birthday"/>
  9. </van-cell-group>

在渲染性别的时候要对绑定的数据的值进行判断

因为在行内可以通过三元表达式

<van-cell is-link title = "性别" :value = "userInfo.gender === 0?'男':'女'"/>

5.6 mapState整合

1.导入mapstate函数

  1. import { mapState } from 'vuex'

2.整合computed

  1. computed: mapState(['userInfo']),
  2. //因为只有一个数据所以不用使用对象和拓展运算符直接进行复制操作
  3. // 之前的定义
  4. //computed: {
  5. // // 在计算属性内部定义一个方法,调用时不需要加括号
  6. // userInfo () {
  7. // return this.$store.state.userInfo
  8. // }
  9. // },

5.7用户信息请求请求优化

(2到1)-- 登陆判断

在router的index.js对用户信息进行判断

一次是在user页面,一次是在编辑页面

1.user页面的请求

  1. computed: {
  2. userInfo () {
  3. return this.$store.state.userInfo
  4. }
  5. },

2.编辑页面的请求

  1. computed: {
  2. // 在计算属性内部定义一个方法,调用时不需要加括号
  3. userInfo () {
  4. return this.$store.state.userInfo
  5. }
  6. },

3.优化之后

  1. // 为了防止重复的对用户信息发起请求,
  2. if (store.state.userInfo.name) {
  3. return next
  4. }
  5. // 不能通过 store.state.userInfo 来判断,因为是个空对象,空对象判断之后也是true
  6. //return可以打断代码不再往下执行,而且如果有用户信息证明一定有正确的token
  7. //console.log({}===true)//true

5.8 编辑用户名

1.dialog弹出模态框

实现结构

​ 1.绑定点击事件

  1. <van-cell is-link title = "名称" :value = "userInfo.name" @click = "showEditName"/>

​ 2.整合用户名编辑框

  1. <!--姓名编辑框-->
  2. <van-dialog v-model = "showName" title = "修改姓名" show-cancel-button>
  3. <van-field ref = "nameField" v-model = "name" placeholder = "请输入用户名"/>
  4. </van-dialog>

2.cell绑定点击事件

1.弹框

2.用户的信息填入输入框

3.输入框获取焦点

​ 设置filed框设置ref

​ this.$refs.属性名获取标签添加点击事件

实现逻辑

  1. data () {
  2. return {
  3. showName: false,
  4. name: ''
  5. }
  6. },
  7. methods : {
  8. showEditName () {
  9. //点击模态框,修改showName的属性为true
  10. this.showName = true
  11. //获取用户信息的name赋值给定义的name数据
  12. this.name = this.userInfo.name
  13. this.$nextTick(() => {
  14. this.$refs.nameField.focus()
  15. })
  16. }
  17. }

4.修改模态框的样式

​ 边框

​ 父盒子设置内边距

  1. .van-dialog__content {
  2. padding: 10px;
  3. }
  4. .van-field {
  5. border: 1px solid #ccc;
  6. }

3.注意事项

vue更新数据和更新dom是异步的

vue数据更新--->dom更新是异步的

可以通过$nextTick注册一个回调函数

dom更新之后执行

5.9 抽取edit的api

方便发起请求和维护

1.设置请求拦截器的信息

2.封装编辑用户信息的请求方法

  1. // 导入
  2. import axios from 'axios'
  3. // 导入token工具函数
  4. import { getToken } from '../utils/token'
  5. // create方法设置基地址的请求request
  6. const request = axios.create({
  7. baseURL: 'http://toutiao-app.itheima.net'
  8. })
  9. // 注册拦截器
  10. // 添加请求拦截器
  11. request.interceptors.request.use(
  12. function (config) {
  13. // 在发送请求之前做些什么
  14. console.log('请求拦截器执行啦')
  15. //设置请求拦截器的信息token令牌!!!
  16. config.headers.Authorization = `Bearer ${getToken().token}`
  17. return config
  18. },
  19. function (error) {
  20. // 对请求错误做些什么
  21. return Promise.reject(error)
  22. }
  23. )
  24. // 抽取方法 - 编辑用户信息
  25. const editUserInfo = data => {
  26. return request({
  27. url: '/v1_0/user/profile',
  28. //后台文档定义的请求方式
  29. method: 'patch',
  30. // data:{...data}不缩写的参数
  31. datadata
  32. })
  33. }
  34. // 暴露出去
  35. export { editUserInfo }

5.10 保存用户名数据

实现结构

添加修改昵称的事件

  1. //显示编辑的用户名
  2. <van-cell is-link title = "名称" :value = "userInfo.name" @click = "showEditName"/>
  3. //保存修改后的用户名
  4. <van-dialog v-model = "showName" title = "修改姓名" show-cancel-button @confirm = "saveNameEdit">

实现逻辑


  1. //显示编辑的用户名
  2. showEditName () {
  3. this.showName = true
  4. this.name = this.userInfo.name
  5. this.$nextTick(() => {
  6. this.$refs.nameField.focus()
  7. })
  8. }
  9. // 定义一个保存用户名的方法
  10. saveNameEdit () {
  11. // 发起修改数据的请求,传入已经存在的值
  12. editUserInfo({ name: this.name })
  13. // 请求成功之后返回数据,在then回调中处理
  14. .then(res => {
  15. // 在仓库中更新用户的信息
  16. this.$store.commit('setUserInfo', {
  17. // 展开所有的用户信息
  18. ...this.userInfo,
  19. // 覆盖用户的昵称信息
  20. name: this.name
  21. })
  22. })
  23. },

5.11 编辑性别信息

实现结构

  1. <van-cell is-link title = "性别" :value = "userInfo.gender === 0?'男':'女'" @click = "showGender = true"/>
  2. //popup编辑框
  3. <van-popup v-model = "showGender" position = "bottom">
  4. <van-nav-bar title = "修改性别" left-text = "取消"/>
  5. <van-cell-group>
  6. <van-cell title = "男" is-link/>
  7. <van-cell title = "女" is-link/>
  8. </van-cell-group>
  9. </van-popup>

实现逻辑

  1. //在data中定义
  2. showGender: false,

点击切换cell组件,修改popub的布尔值,切换弹出的状态

跳转不了看一下路由router

5.12保存性别信息

1.修改数据库中的数据

2.关闭显示的模态框(点击取消,男,女)

实现结构

  1. 1.<!--在渲染性别的时候要对绑定的数据的值进行判断 因为在行内可以通过三元表达式,在点击性别的时候显示性别框-->
  2. <van-cell is-link title = "性别" :value = "userInfo.gender === 0?'男':'女'" @click = "showGender = true"/>
  3. //2.
  4. <van-nav-bar title = "修改性别" left-text = "取消" @click-left = "showGender = false"/>
  5. //3.
  6. <van-cell-group>
  7. <van-cell title = "男" is-link @click = "saveGenderEdit(0)"/>
  8. <van-cell title = "女" is-link @click = "saveGenderEdit(1)"/>
  9. </van-cell-group>

实现逻辑

  1. saveGenderEdit (gender) {
  2. editUserInfo({ gender }).then(res => {
  3. this.showGender = false
  4. this.$store.commit('setUserInfo', {
  5. // 展开所有的用户信息
  6. ...this.userInfo,
  7. // 覆盖用户的性别信息
  8. gender
  9. })
  10. })
  11. },

5.13编辑日期

  1. data(){
  2. birthday: '',
  3. minDate: new Date(1970, 0, 1)//设置最小值,月份从0开始,看文档
  4. }
  5. showBirthdayPop () {
  6. this.showBirthday = true
  7. this.birthday = this.userInfo.birthday
  8. }
  1. <van-cell is-link title = "生日" :value = "userInfo.birthday" @click="showBirthdayPop"/>//为生日模态框绑定点击事件
  2. <!--生日编辑框-->
  3. <van-popup v-model = "birthday" position = "bottom">
  4. <van-datetime-picker
  5. v-model = "birthday"
  6. type = "date"
  7. title = "选择年月日"
  8. :min-date = "minDate"
  9. />
  10. </van-popup>

5.14保存编辑日期

实现结构

  1. <van-datetime-picker
  2. v-model = "birthday"
  3. type = "date"
  4. title = "选择年月日"
  5. :min-date = "minDate"
  6. @cancel = "showBirthday = false"
  7. @confirm = "saveBirthday"
  8. />

实现逻辑

  1. saveBirthday () {
  2. // 处理生日的格式,符合要求
  3. const birthday = moment(this.birthday).format('YYYY-MM-DD')
  4. editUserInfo({ birthday }).then(res => {
  5. this.showBirthday = false
  6. this.$store.commit('setUserInfo', {
  7. ...this.userInfo,
  8. birthday
  9. })
  10. })
  11. }

6.xxx

7.知识点的补充

1.具名插槽

2.axios-create创建实例

​ 通过axios-create创建实例来抽取api

this.$axios的方式调用接口会有两个问题

​ 1.没有办法在审查代码时立即定位

​ 2.修改参数、地址比较麻烦,不利于后期的维护

抽取案例

3.轻提示toast

4.vuex的基本使用

Vuex是什么:

​ Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。Vuex 和单纯的全局对象有以下两点不同:

  1. Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
  2. 你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用

基础使用

​ 1.在main.js中声明以store仓库,通过Vue的store方法,传入参数对象count,这样就可以在main.js之外的页面使用count

  1. <div class = "info-box">
  2. <van-image
  3. class = "my-image"
  4. round
  5. :src = "userInfo.photo"
  6. />
  7. <h2 class = "name">
  8. {{ userInfo.name }}
  9. <br>
  10. <van-tag color = "#fff" text-color = "#3296fa" type = "primary"> {{ userInfo.birthday }}</van-tag>
  11. </h2>
  12. </div>

在其他页面通过语句

this.$store.state.xxx修改和获取数据

5.嵌套路由

目的:为了搭建更为复杂的项目

语法:

  1. /login登录页
  2. /home首页
    1. /home/index
    2. /home/news
    3. /home/vip
    4. /home/hots
      1. router-view
  1. // 嵌套路由的规则
  2. import index from '../views/home/index/index.vue'
  3. import news from '../views/home/news'
  4. import vip from '../views/home/vip'
  5. import hots from '../views/home/hots'
  6. Vue.use(VueRouter)
  7. const routes = [
  8. {
  9. path: '/login',
  10. name: 'login',
  11. component: login
  12. },
  13. {
  14. path: '/home',
  15. name: 'home',
  16. component: home,
  17. //通过children对象来设置嵌套路由的地址
  18. children: [
  19. {
  20. path: 'index', // /home/index
  21. component: index
  22. },
  23. {
  24. path: 'news', // /home/news
  25. component: news
  26. },
  27. {
  28. path: 'vip', // /home/vip
  29. component: vip
  30. },
  31. {
  32. path: 'hots', // /home/hots
  33. component: hots
  34. }
  35. ]
  36. }
  37. ]
  38. const router = new VueRouter({
  39. routes
  40. })
  41. export default router

6.路由元信息

Router中的mata

是一个对象

与path、name、component同级

7.导航守卫

Router中的,

不止一个导航守卫

三个参数:

​ 1.to去的路由信息

​ 2.from来的路由信息

​ 3.next()是否继续执行

语法

  1. const router = new VueRouter({
  2. routes
  3. })
  4. // 添加全局前置守卫
  5. router.beforeEach((to, from, next) => {
  6. // to 即将到达的路由信息 this.$route获取到的是一致的
  7. console.log('to:', to)
  8. // from 离开的路由信息 this.$route获取到的是一致的
  9. console.log('from:', from)
  10. // console.log('next:', next)
  11. // 不执行next 卡在这个地方 路由的切换就有问题啦!
  12. // next(),类似于node中的中间件,如果没有next到这就停了
  13. // 如果你要去的就是 404 直接放走
  14. if (to.path === '/404') {
  15. // 直接放走
  16. next()
  17. } else {
  18. // 除他之外 去404
  19. // 直接跳转到指定页面
  20. next({ path: '/404' })
  21. }
  22. })

导航守卫有多个,不止是beforeEach()

8.vuex的mutations

主要作用是修改数据

this.$store.state.xxx取值/赋值

这种方法可以修改,但是插件无法捕捉,不方便调试和修改

2.组件中调用这个方法

this.$store.commit('mutations',参数)取值/赋值

实现原理

setFood要和mutation中一样,state是被修改的数据,setFood方法内将传进的数据参数对原始state数据进行赋值修改

类似于

​ this.$emit()

9.Vuex的mapState辅助函数

意义:方便计算属性的定义取值

作用:

​ 1.自动生成计算属性:this.$store.state.userInfo

​ 2.直接通过mapState({'userInfo'})获取仓库的数据

​ 返回值:

​ {userIfo:function(){return this.$store.state.userInfo}}

展开了对象{food:f}

food:function(){}

辅助函数的两种方法

1.有自己的数据要绑定,通过展开运算符

  1. computed: {
  2. //本地的计算属性
  3. localComputed () { /* ... */ },
  4. // 使用对象展开运算符将此对象混入到外部对象中
  5. ...mapState({
  6. // ...
  7. })
  8. }

2.没有自己的数据直接使用

  1. computed: mapState([
  2. // 映射 this.count 为 store.state.count
  3. 'state中保存的名字'
  4. ])

10.axios的拦截器

逻辑关系

实现代码

  1. // 添加请求拦截器
  2. axios.interceptors.request.use(function (config) {
  3. // 在发送请求之前做些什么
  4. return config;
  5. }, function (error) {
  6. // 对请求错误做些什么
  7. return Promise.reject(error);
  8. });
  9. // 添加响应拦截器
  10. axios.interceptors.response.use(function (response) {
  11. // 对响应数据做点什么
  12. return response;
  13. }, function (error) {
  14. // 对响应错误做点什么
  15. return Promise.reject(error);
  16. });

11.点击user无效

在晚上点击user按钮之后没有任何的反应(一段时间之后会报错),首先是服务器的响应失效了。

没有任何反应的原因是,在单击我的之后。user的vue页面一直在发送请求但是没有请求到数据,所以一直在等待加载被

  1. if (store.state.userInfo.name) {
  2. return next()
  3. }

卡住了,请求不到用户的名字,就不能next,所以一直在等待请求

页面有四种方法到指定页面但是都不符合

​ 1.不要登陆(不符合)

​ 2.有请求的用户信息名称(不符合)

​ 3.没有token next跳转到login(不符合)

​ 4.定义的方法没有调用所以不饿能next(不符合)

Headline 项目总结中的更多相关文章

  1. iOS项目开发中的知识点与问题收集整理①(Part 一)

    前言部分 注:本文并非绝对原创 大部分内容摘自 http://blog.csdn.net/hengshujiyi/article/details/20943045 文中有些方法可能已过时并不适用于现在 ...

  2. J2EE项目开发中常用到的公共方法

    在项目IDCM中涉及到多种工单,包括有:服务器|网络设备上下架工单.服务器|网络设备重启工单.服务器光纤网线更换工单.网络设备撤线布线工单.服务器|网络设备替换工单.服务器|网络设备RMA工单.通用原 ...

  3. [Visual Studio]项目属性中继承的值怎么删除

    遇到一个问题,莫名奇妙编译,却出错"找不到包含文件<winapifamily.h>",之前从没出过问题啊!百思不得其解. 研究包含winapifamily的位置,发现有 ...

  4. JavaWeb 项目开发中的技术总结

    前言: 在项目开发过程中的一点点指导思想 1.环境准备 win系统 Eclipse 开发平台 maven tomcat Mysql 数据库,mysql5.6 操作数据库的jar 包 JDBC 连接数据 ...

  5. 团队项目开发中,常见的版本控制有svn,git

    团队项目开发中,常见的版本控制有svn,git

  6. 在OC项目工程中混编Swift

    1.创建一个OC项目工程,然后在Build Settings中找到如下字段,修改. 2.然后在项目中创建swift文件,如果系统提示是否需要创建桥接文件的时候,点击确定. 然后在Build Setti ...

  7. 基于Server-Sent Event的简单聊天室 Web 2.0时代,即时通信已经成为必不可少的网站功能,那实现Web即时通信的机制有哪些呢?在这门项目课中我们将一一介绍。最后我们将会实现一个基于Server-Sent Event和Flask简单的在线聊天室。

    基于Server-Sent Event的简单聊天室 Web 2.0时代,即时通信已经成为必不可少的网站功能,那实现Web即时通信的机制有哪些呢?在这门项目课中我们将一一介绍.最后我们将会实现一个基于S ...

  8. 项目实践中--Git服务器的搭建与使用指南(转)

    一.前言 Git是一款免费.开源的分布式版本控制系统,用以有效.高速的处理从很小到非常大的项目版本管理.在平时的项目开发中,我们会使用到Git来进行版本控制. Git的功能特性: 从一般开发者的角度来 ...

  9. “ddl”有一个无效 SelectedValue,因为它不在项目列表中。

    “ddl_ekt”有一个无效 SelectedValue,因为它不在项目列表中. 怎么回事 现象: 在用户控件的page_load事件里绑定下拉框,报上面错误 解决: 将下拉框绑定,放在page_In ...

随机推荐

  1. 逆向 stdio.h 函数库 fseek 函数(调试版本)

    0x01 fseek 函数 函数原型:int fseek(FILE *stream, long int offset, int whence) 函数功能:设置流 stream 的文件位置为给定的偏移 ...

  2. jquery遍历json的几种方法

    for循环: 1 <script> 2 var obj = { 3 "status":1, 4 "bkmsg":"\u6210\u529f ...

  3. 记一次CTF的签到题

    开篇 打开题目网站 首先看到的是一个人博客,功能点非常少,功能较多的页面就是留言板了 一开始没啥思路,就想着抓包能不能找到SQL注入无果,在这个地方卡了很久 柳暗花明 在乱点的时候,无意中发现题目中的 ...

  4. 北航OO(2020)第四单元博客作业暨学期总结

    一.第四单元架构设计 1.第一次作业 我在本次作业中设置了多个储存结构:Directory,ElementsInName,ElementsInId,Cache. Directory: 顾名思义,这是个 ...

  5. .Net Core with 微服务 - 架构图

    上一次我们简单介绍了什么是微服务(.NET Core with 微服务 - 什么是微服务 ).介绍了微服务的来龙去脉,一些基础性的概念.有大佬在评论区指出说这根本不是微服务.由于本人的能力有限,大概也 ...

  6. .Net Core——用代码写代码?

    想要用代码写代码,肯定是绕不开反射的.反射的概念相比都不陌生,只是应用多少就因人而异,今天分享一个代码生成器的思路,仅供参考,不要过分依赖哦. 思路分析 众所周知,利用反射可以在程序运行时获取到任一对 ...

  7. 使用JSONassert进行JSON对象对比

      在日常工作中,会接到用户提出一张订单,修改后需要记录每次修改的信息,然后需要查看修改前后的差异信息这样的需求.要实现这样的功能方式有很多.下面介绍下JSONassert的简单使用,也方便自己后续使 ...

  8. [bug] Maven每次都自动下载jar包非常慢

    解决 方法一:将maven改为离线模式,自己下载jar包复制到仓库中 eclipse中Window>preferences>maven>勾选Offline 方法二:将maven镜像改 ...

  9. 测试 USB 存储设备读写性能(Mb/s),平均读写速度等

    1.将U盘(USB3.0)插入被测试机器,假定识别设备为sdc2.创建vfat文件系统分区/dev/sdb1分区容量大于30GBumount /dev/sdc1mkfs -t vfat /dev/sd ...

  10. MyBatis 模糊查询的 4 种实现方式

    引言 MyBatis 有 4 种方式可以实现模糊查询. 员工信息表 ( tb_employee ) 如下: id name sex email birthday address 001 张一凡 男 z ...