Vue2.0 项目实战篇-学不会算我的;

Vue2.0 项目实战篇-学不会算我的;

本篇文章学习记录于: bilibili-黑马程序♞ 104-139集 》》🎯目标:冲击前后端全栈🔥,分享一下学过程:

Java.慈祥的博客——个人前端技术栈blog记录:、感谢黑马官方分享的课程,ありがとうございました 🦀🦀🦀

项目初始化

项目名: 智慧商城项目——shop-project

接口文档: https://apifox.com/apidoc/shared-12ab6b18-adc2-444c-ad11-0e60f5693f66/doc-2221080

  • 为了方便开发,此处使用黑马官方提供的接口文档,不确定接口稳定性,有时间开发一个后端Demo吧w(゚Д゚)w~~
  • 智慧商城 (itheima.net) 黑马官网展示Demo,实在不行去这里Copy接口使用,链接不稳定,可能会消失
  • 根据blog留言、如果多的话考虑写一套:node+express接口Demo

项目功能演示:

在这里插入图片描述

vue-cli 建项目:

基于Vue-cli 自定义创建项目:

#npm安装脚手架:
npm i @vue/cli -g		#以及安装,请忽略;

#使用: vue-cli 创建项目:
vue create shop-project	#选择Vue2版本、依赖配置:es6-es3、路由、less/css、eslint校验格式 感觉没啥用)
#Use history mode for router!  		==>		是否使用history模式;
#Pick a CSS pre-processor 			==>		选择css预处理;
#Pick a linter/formatter config		==>		选择eslint的风格;
#Pick a additional lint features	==>		选择校验的时机: Lint a save 开启保存即校验;
#Where do you prefer placing config for Babel ESlint etc? 配置文件的生成方式>In dedicated config files
#Save this as a preset for future projects? 是否保存预设,下次直接使用> 不保存,输入 N

在这里插入图片描述

初始化项目文件目录:

🆗,上述使用Vue-cli简单的构建了项目结构,但还单单不满足一个项目的需求,让我们稍稍的修改⚒️:

删除一些不需要的初始化目录、修改没删除的文件、新增需要的目录结构 实际开发按需求而自定义;

新增目录结构: src/api 存储接口模块,定义ajax请求接口的模块)src/utils 定义公共工具模块)

在这里插入图片描述

Vant 组件库\使用:

因为本人也是刚开始接触前端,早就听说组件库的强大; 让新手也可以轻松的制作出,非常Nice的页面;

后端宝宝,还在酷酷加班写: 数据库Sql、涉及接口、梳理业务、前端宝宝已经在泡咖啡、打王者了🎮;

什么是组件库: 组件库是一套预先设计和实现好的UI组件集合,这些组件是构建用户界面的基本单元;

  • 它们提供一套标准化、可复用的界面元素,以促进软件开发过程中的效率、一致性和可维护性;
  • 包括但不限于按钮、输入框、导航栏、对话框、表格、卡片等;

在实际开发中: 组件库如:

Vant 是由有赞前端团队开发的,专为移动应用设计的Vue.js组件库:

Vant有很多版本,Vue2、Vue3、小程序,都有兼容:Vue2==>Vant2Vue3==>Vant4 使用;

Vant是一个成熟、高效且功能丰富的Vue.js组件库,拥有活跃的社区支持,不断更新的组件和文档;

在这里插入图片描述

Vant 组件导入\使用:

Vant的官网已经介绍的很完美了,此处简单介绍一下: 首先,通过 npmyarn 安装Vant,官网安装方式也有很多;

#Vue 2项目安装 Vant2
npm i vant@latest-v2 -S
yarn add vant@latest-v2		#省略...脚手架、CDN安装;

安装完之后就可以在项目中导入组件: Vant支持全部导入、按需导入,注意:这并不是Vue组件的全局导入、局部导入;

  • 全部导入: Vant 支持一次性导入所有组件,引入所有组件会增加代码包体积,因此不推荐这种做法;
  • 按需导入: 按需导入只会导入你使用的组件,进而节约了资源;

Vant 全部导入:

全部导入: 通常采用全局导入形式,在main.JS 中定义,这样就可以在项目的任意位置,直接使用;

//mainJS中引入Vant全部组件,注册至全局使用;
import 'vant/lib/index.css';
import Vant from 'vant';
Vue.use(Vant);

在这里插入图片描述

Vant 按需导入:

按需导入: 虽然没有全部导入方便,但节省资源推荐使用;

首先安装依赖: yarn add babel-plugin-import -Dbabel.config.js中配置:

//它会在编译过程中将 import 的写法自动转换为按需引入的方式
module.exports = {
  presets: [
    '@vue/cli-plugin-babel/preset'
  ],
  plugins: [
    ['import', {
      libraryName: 'vant',
      libraryDirectory: 'es',
      style: true
    }, 'vant']
  ]
}

最后,为了方便在全局使用,在main.JS 中全局注册需要的组件模块: import { 组件1, 组件2, ... } from 'vant'

//mainJS中按需引入Vant组件,注册至全局使用;
import { Button,Slider } from 'vant';
Vue.use(Button);
Vue.use(Slider);

在这里插入图片描述

优化按需导入:

伴随着项目越来越大,按需导入的组件模块: 越来越多,导致main.JS 不方便维护,

实际情况可以将:导入组件的代码单独抽离出一个新的配置文件中进行管理,utils/vant-ui.JS

import Vue from 'vue'
import { Button, Icon } from 'vant'
Vue.use(Button)
Vue.use(Icon)

main文件中引入:utils/vant-ui.JS import '@/utils/vant-ui'
在这里插入图片描述

项目中的vw布局适配:

因为:本项目针对移动应用📱,而不同厂商的设备会有大小区别,所以存在不同设备显示效果不同🚫

当然,这个在属于前端领域常见的问题: 也是最开始学习前端,最让我头疼的问题;

于是:诞生了——>PostCSS VW插件: 实现的CSS单位转换技术,

  • 它允许开发者将CSS中的像素单位px,自动转换为,视口宽度==>单位vw

  • vw (Viewport Width)视口单位是一种响应式设计的工具,其中vw代表视口宽度的百分比:1vw = 视口宽度的1%

  • 响应式布局: 能够根据屏幕尺寸自动调整元素的大小,从而减少手动添加媒体查询或特定设备前缀的需求;

使用PostCSS VW插件

安装插件: 首先,需要在项目中安装PostCSS及其对应的vw转换插件,GitHub项目地址 🪜🪄

npm install postcss-px-to-viewport --save-dev	#npm  安装、或
yarn add postcss-px-to-viewport --dev			#yarn 安装

配置PostCSS: 在项目的构建配置文件中:webpackvue.config.jspostcss.config.js)

项目根目录创建: postcss.config.js 配置文件📄

module.exports = {
  plugins: {
	//适配的标准屏的宽度 iphoneX:375    
    'postcss-px-to-viewport': {
      viewportWidth: 375,
        /**     更多配置
        viewportHeight: 1334, 	// 可选,设计稿高度
        unitPrecision: 5, 		// 转换后的vw单位的小数位数
        viewportUnit: 'vw', 	// 转换的目标单位
        selectorBlackList: [], 	// 不转换选择器列表
        minPixelValue: 1, 		// 小于1px的值不转换
        mediaQuery: true, 		// 是否转换媒体查询中的px
        replace: true, 			// 是否直接替换px单位
        exclude: [/node_modules/], // 排除某些文件夹下的文件 		*/
    },
  },
};

在这里插入图片描述

注意事项:

对于字体大小等,可能需要更细致的控制,避免在极小或极大屏幕上出现阅读困难;

使用vw时,需要考虑最小设备的兼容性,确保在小屏幕设备上元素不会变得过小而难以阅读或操作;

在某些特定场景下,如需要精确像素对齐时,直接使用vw可能不是最佳选择,需要结合其他单位使用;

项目路由配置\定义:

在这里插入图片描述

路由设计: 但凡是单个页面,独立展示的,都是一级路由,为了方便管理:一级路由,定义为文件夹、index.vue主页面

二级路由: 定义在所属的一级路由目录下;——————创建文件

my-app/
│
├── src/
│   ├── router/               		# 定义路由组件配置
│   │   ├── index.js
│   ├── views/                     	# 定义路由模块页面
│   │   ├── login/						#登录模块
│   │   │   │   ├── index.vue
│   │   └── layout/						#首页模块——内涵多个二级子模块;
│   │   │   │   ├── index.vue
│   │   │   │   ├── 首页.vue
│   │   │   │   ├── 我的.vue
│   │   │   │   ├── 购物车.vue
│   │   │   │   ├── 分类页.vue
│   │   └── pay/						#支付模块
│   │   │   │   ├── index.vue
│   │   └── sarch/						#搜索模块--内有搜索页、搜索列表页一级目录
│   │   │   │   ├── index.vue
│   │   │   │   ├── list.vue
│   │   └── myorder/					#订单模块
│   │   │   │   ├── index.vue
│   │   └── prodetail/					#商品模块——商品详情页,描述固定商品所以需要传递ID
│   │   │   │   ├── index.vue
│   ├── App.vue                     # 主页面
│   ├── main.js                     # 主配置文件

配置src/router/index.js

//省略导入路由配置:
const router = new VueRouter({
  routes: [
    // '/' 表示默认页
    { path: '/', component: Layout },
    { path: '/login', component: Login },
    { path: '/search', component: Search },
    { path: '/searchlist', component: SearchList },
    // 动态路由传参,确认将来是哪个商品,路由参数中携带 id
    { path: '/prodetail/:id', component: ProDetail },
    { path: '/myorder', component: MyOrder },
    { path: '/pay', component: Pay }
  ]
})

在这里插入图片描述

Vant定义:首页架子;

Vant 组件神通广大的集成了:底部导航、并支持路由配置: 🙏感谢开发者,伟大的组件之神~

Vant导航-组件:Tabbar: Vant 2 - 轻量、可靠的移动端组件库 (vant-ui.github.io) vant-ui.js 引入组件;

import Vue from 'vue'
import { Button,Slider,Tabbar,TabbarItem } from 'vant';
Vue.use(Button);
Vue.use(Slider);
Vue.use(Tabbar);
Vue.use(TabbarItem);

定义layout首页: 定义二级组件文件、配置二级路由…省略…),并定义首页结构:使用Vant导航组合组件;

<template>
  <div>
    <!-- 二级路由的位置 -->
    <router-view></router-view>
    <!-- active-color	选中标签的颜色\inactive-color	未选中标签的颜色 -->
    <van-tabbar route active-color="#ee0a24" inactive-color="#000">
      <!-- 通过 icon 插槽自定义图标 -->
      <!-- 标签栏支持路由模式,用于搭配 vue-router 使用
           路由模式下会匹配页面路径和标签的 to 属性,并自动选中对应的标签 -->
      <van-tabbar-item to="/home" icon="wap-home-o">首页</van-tabbar-item>
      <van-tabbar-item to="/category" icon="apps-o">分类页</van-tabbar-item>
      <van-tabbar-item to="/cart" icon="shopping-cart-o">购物车</van-tabbar-item>
      <van-tabbar-item to="/user" icon="user-o">我的</van-tabbar-item>
    </van-tabbar>
  </div>
</template>
<script>
  export default { name: 'LayoutIndex' }
</script>
<style></style>

在这里插入图片描述

登录页面静态布局:

🆗,上述架子搭建的差不多了,下面开始进行页面填充开发——为了节省时间,下面开始CV战士了🗂️——Copy代码了:

全局样式配置:

既然要开发页面,难免会存在公共的样式配置: 每个页面都会有头部导航,方便进行页面返回、标题提醒;

当然,Vant组件也提供了: NavBar 导航栏:引入组件、页面中导入;且几乎所有页面都会有头部导航;

此时,如果需要对头部样式进行调整,迫切需要一个全局的样式,进行统一配置管理;

  • 创建文件夹/文件:src/styles/common.less 公共样式文件;
  • 最后,别忘了引入:main.JS文件:import '@/styles/common.less'
//src/styles/common.less 项目全局样式配置
//去除内外边距、盒子样式
* { margin: 0; padding: 0; box-sizing: border-box; }
//文字溢出省略号样式
.text-ellipsis-2 {
  overflow: hidden; -webkit-line-clamp: 2;
  text-overflow: ellipsis; display: -webkit-box; -webkit-box-orient: vertical;
}
//Vant导航通用样式
.van-nav-bar {
  //设置头部导航 < 颜色;
  .van-nav-bar__arrow { color: #333; }
}

Copy登录页面代码、导入项目所需图片、请求查看页面: http://localhost:8080/#/login

在这里插入图片描述

request模块axios封装

实际开发过程中,我们通常会将: axios 进行封装成一个模块进行使用,主要出于以下几个关键原因:

  • 统一配置: 通过封装,可以统一管理API请求设置统一的基础URL、默认配置

    如:超时时间、headers等、以及处理跨域问题,开发者无需在重复这些配置,提高了代码的可维护性;

  • 多环境配置: 随着项目业务越来越大可能:一个前端会有多个服务器配置,定义封装axios 实现多数据源;

  • 环境变量管理: 在不同的环境:开发测试生产,基础URL和其他配置可能不同,封装可以轻松地环境变量切换;

定义\封装axios:

首先,安装axios依赖: npm install axiosyarn add axios

新建 src/utils/request.js 封装 axios 模块: 利用 axios.create 创建一个自定义的 axios 来使用;

/** 封装axios 
 *  后端基地址: https://smart-shop.itheima.net/index.php?s=/api */
import axios from 'axios'
// 创建 axios 实例,将来对创建出来的实例,进行自定义配置
// 好处:不会污染原始的 axios 实例
const instance = axios.create({
    baseURL: 'https://smart-shop.itheima.net/index.php?s=/api/',
    timeout: 5000
})
 
// 自定义配置 - 请求/响应 拦截器
// 添加请求拦截器
instance.interceptors.request.use(function (config) {
    // 在发送请求之前做些什么
    return config
}, function (error) {
    // 对请求错误做些什么
    return Promise.reject(error)
})

// 添加响应拦截器
instance.interceptors.response.use(function (response) {
    // 2xx 范围内的状态码都会触发该函数。
    // 对响应数据做点什么 (默认axios会多包装一层data,需要响应拦截器中处理一下)
    return response.data;
}, function (error) {
    // 超出 2xx 范围的状态码都会触发该函数
    return Promise.reject(error);
})

// 导出配置好的实例
export default instance

src/views/login/index.vue: 登录页面,导入模块、发送获取验证码图片请求;

<template>
  <div class="login">
	    <!-- ..省略部分代码.. -->
        <div class="form-item">
          <input class="inp" maxlength="5" placeholder="请输入图形验证码" type="text">
          <img v-if="picUrl" :src="picUrl" @click="getPicCode">
        </div>
      	<!-- ..省略部分代码.. -->
    </div>
  </div>
</template>
<script>
  //导入request封装的axios模块;
  import request from '@/utils/request'

  export default { 
    name: 'LoginPage',
    //钩子函数页面初始化,获取验证码图片;
    async created () { this.getPicCode() },
    data(){ return { picUrl: '', picKey: '' } },
    methods: {
      //获取验证码图片;
      async getPicCode () {  
        const { data:{ base64,key }} = await request.get('/captcha/image');  //解构赋值获取图片信息;
        this.picUrl = base64
        this.picKey = key
    },
    }
  }
</script>

在这里插入图片描述

基于请求回来的 base64 图片,实现图形验证码功能:

图形验证码,本质就是一个请求回来的图片,用户将来输入图形验证码,用于强制人机交互,可以抵御机器自动化攻击;

动态将请求回来的 base64 图片,解析渲染出来,base64 图片base64编码、可以直接给img src使用key图片唯一标识

优化—图片验证码接口

使用:api接口 - 封装图片验证码接口: 实际开发过程中,经常会遇到一个接口很多模块都会使用,

且频繁,在页面中定义请求接口,页面中充斥着请求代码,可阅读性不高;

所以: 优化,将请求封装成方法,统一存放到 api 模块,与页面分离;

具体实现: 新建 api/login.js 提供获取图形验证码 ``API`函数;

import request from '@/utils/request'

// 获取图形验证码
export const getPicCode = () => {
  return request.get('/captcha/image')
}

src/views/login/index.vue页面中调用测试:

//导入api/login.js 登录接口模块,并选择需要的函数对象引入
import { getPicCode } from '@/api/login'

//获取验证码图片;
async getPicCode () {  
    const { data:{ base64,key }} = await getPicCode();  //调用登录接口模块接口函数;
    this.picUrl = base64
    this.picKey = key
},

在这里插入图片描述

登录—>短信\认证

📲短信认证,大家都不陌生吧: 用户输入手机号进行、后端服务器——调用第三方短信服务,给手机发送验证短信;

用户输入短信——提交后端验证请求——通过,登录成功!!如此:简单一个功能,其实在前后端要经历一番不小的折腾;

  • 后端,这里就不介绍了,也不能提供真实的短信接口,统一默认此案例短信: 246810

  • 前端,要做的有: 确认输入框手机号码正确、请求短信、验证60秒倒计==>实际情况后端也会处理)

前端短信认证:

确认输入框手机号码正确: 如果不正确通过,Vant—Toast组件消息提醒;

点击:获取验证码==> 开始验证倒计时、并发送短信获取验证码;

在这里插入图片描述

封装api-短信请求:

api/login.js 封装短信请求接口: 需要三个参数:图形唯一Key图形验证码手机号码 后端也要进行图形验证码校验;

export const getMsgCode = (captchaCode, captchaKey, mobile) => {
  return request.post('/captcha/sendSmsCaptcha', {
    form: { captchaCode, captchaKey, mobile }
  })
}

页面中:login/index.vue: 引入接口模块,并调用请求接口,测试环境验证码始终为: 246810

//导入api/login.js 登录接口模块,并选择需要的函数对象引入
import { getPicCode,getMsgCode } from '@/api/login'
//省略部分代码....
export default {
    //省略部分代码....
	methods: {
        //点击:获取验证码
        async getCode () {  
          //验证手机号码合法性
          if (!this.validFn()) { return }
          //避免重复倒计时,发送请求: 
          //判断当前目前没有定时器开 且 totalSecond 和 second 一致秒数归位)
          if (!this.timer && this.second === this.totalSecond) {
            //发送请求...开启倒计时1000毫秒触发1次;
         	await getMsgCode(this.picCode, this.picKey, this.mobile)
	        this.$toast('短信发送成功,注意查收')
            //每秒-1 秒到至≤0 清理定时器,重置数据;
            this.timer = setInterval(() => {
              this.second--                         
              if (this.second <= 0) {     
                clearInterval(this.timer);
                this.timer = null // 重置定时器 id
                this.second = this.totalSecond // 归位
              }
            }, 1000)
          }
        },
    }
}

在这里插入图片描述

封装api-登录请求:

🆗,终于来到了登录请求: 点击登录按钮🕹️,验证手机号、图形码、短信—>携带参数发送请求,后端验证通过、成功登录!

export const codeLogin = (mobile, smsCode) => {
  return request.post('/passport/login', {
    form: {
      isParty: false,   //是否存在第三方用户信息  
      partyData: {},    //三方登录信息
      smsCode,          //短信验证码
      mobile,           //手机号
    }
  })
}

页面中:login/index.vue: 引入接口模块,并调用请求接口;

//<input class="inp" placeholder="请输入短信验证码" type="text" v-model="msgCode" >
//<div class="login-btn" @click="login" >登录</div>
//省略.... v-model表单元素、登录按钮注入函数;

//导入api/login.js 登录接口模块,并选择需要的函数对象引入
import { getPicCode,getMsgCode,login } from '@/api/login'
//省略部分代码....
export default {
    //省略部分代码....
	methods: {
        //点击:登录
        async login(){
          if (!this.validFn()) { return }             //校验手机\图形验证码;
          if (!/^\d{6}$/.test(this.msgCode)) {        //校验短信;
            this.$toast('请输入正确的手机验证码')
            return
          }
          await codeLogin(this.mobile, this.msgCode); //登录请求;
          this.$toast('登录成功');
          this.$router.push('/');                     //路由首页;
        }
    }
}

在这里插入图片描述

请求\响应拦截器处理:

🎉🎉 完成了登录、But有没有发现有一个🐞:好像,无论登录接口请求:成功\失败,都会成功跳转❗❗

在这里插入图片描述

查看代码,因为:我们并没有对接口返回结果进行处理; 解决方案: 登录函数添加

const res = await codeLogin(this.mobile, this.msgCode); //登录请求;
if( res.status!=200 ){ return this.$toast('接口异常、登录失败'); }

可实际开发中,有非常多的接口、每个接口都要进行处理… 有没有更好的解决

还记得上面,封装Axios模块吗? 我们可以对模块进行统一的:请求\响应拦截处理 🧱

  • 添加请求拦截器: 添加 loading 效果、告知用户,加载中—请耐心等待;
  • 添加响应拦截器: 处理接口异常情况\关闭 loading
// 自定义配置 - 请求/响应 拦截器
// 添加请求拦截器: 添加 loading 效果
instance.interceptors.request.use(function (config) {
    Toast.loading({
      message: '加载中...',
      forbidClick: true,      // 禁止背景点击
      duration: 0,            // 不会自动消失
      loadingType: 'spinner', // 配置loading图标
  })
    return config
  }, function (error) {
    // 对请求错误做些什么
    return Promise.reject(error)
})

// 添加响应拦截器: 处理接口异常情况\关闭 loading
instance.interceptors.response.use(function (response) {
  // 2xx 范围内的状态码都会触发该函数
  // 对响应数据做点什么 (默认axios会多包装一层data,需要响应拦截器中处理一下)
  const res = response.data;
  if (res.status !== 200) {
    Toast(res.message);   //Toast给错误提示
    return Promise.reject(res.message);   //抛出一个错误的promise
  } else {
    // 正确情况,直接走业务核心逻辑,清除loading效果
    Toast.clear()
  }
  return res;
  }, function (error) {
    //超出 2xx 范围的状态码都会触发该函数,对响应错误做点什么;
    return Promise.reject(error)
})

在这里插入图片描述

注意: 实际开发,接口异常提示消息,请与前后端协调处理…

登录权证—信息存储Vuex:

登录\权限\认证: 行外人:简单的业务、行内人:后端?前端?交互校验???

登录—是开发过程中最让人头疼的事情了, 因为看似非常简单一个业务逻辑,内部有非常多的规则控制;

一体式项目、前后端分离项目、分布式、微服务、非常混乱: 虽然逻辑类似,处理起来却又有很多细小的控制;

此处介绍,前端登录的处理规则=> 关于后端,这里有一个Node+Express的简单业务流程:Express进阶升级=>会话控制

  • HTTP 是一种无状态的协议,它没有记忆、没有办法区分多次的请求是否来自于同一个客户端, 无法区分用户...
  • A、B 同时登录BiliBili📺 A喜欢看鬼畜👻、B喜欢看番剧🍅【都收藏了很多视频…】
  • 但是,HTTP是无状态的每次请求都是一个新的开始,从而无法记录收藏记录🪶…
  • 我们迫切的需要一种东西,可以用来判断用户状态,记录用户信息

所以: 在用户登录,服务器会返回给我们一个:token令牌🛡︎,之后的每次请求,都携带这个令牌🛡︎

服务器,根据令牌🛡︎: 验证用户信息,判断用户状态,🆗,大致如此,接下来就来康康这个令牌🛡︎吧;

Vuex 存储管理用户信息:

我们都知道:Vuex: 集中存储组件的数据,相当于一个数据共享的容器,由此:非常适合用来存储,登录成功的Token

新建 vuex user模块 store/modules/user.js: 挂载到 vuex 上、代码省略…)

export default {
  namespaced: true,
  state () {
    return {
      // 个人权证相关
      userInfo: { token: '', userId: '' }
    }
  },
  mutations: {
    //用于组件修改userInfo信息;
    setUserInfo (state, obj) { state.userInfo = obj }
  },
  actions: {},
  getters: {}
}

页面中:login/index.vue: 用户登录成功,获取用户信息调用Vuex组件函数保存信息;

const res = await codeLogin(this.mobile, this.msgCode); //登录请求;
// if( res.status!=200 ){ return this.$toast('接口异常、登录失败'); }   //由响应拦截器统一处理;
this.$store.commit('user/setUserInfo',res.data);                     //调用Vuex模块函数,保存用户信息;

在这里插入图片描述

如此,Vuex支持在项目的任何组件获取数据; 但,还有一个问题,Vuex会被浏览器刷新丢失!!

封装storage模块持久化Vuex:

解决: Vuex会被浏览器刷新丢失!!,将Vuex数据保存至:浏览器—的localStorage,以达到数据持久化的目的;

为什么要封装:localStorage==> 为了方便操作,传统的localStorage使用,根据Key进行读取,不便于操作\管理;

新建 utils/storage.js 封装方法:

//定义用户信息key
const USERINFO_KEY = 'UserinfoKey'

// 设置个人信息
export const setInfo = (info) => { localStorage.setItem(USERINFO_KEY, JSON.stringify(info)) }

// 获取个人信息
export const getInfo = () => {
  //从localStorage获取用户信息,没有则返回空对象;
  const result = localStorage.getItem(USERINFO_KEY);
  return result ? JSON.parse(result) : { token: '', userId: '' }    //三元运算符判断是否存在个人信息返回;
}

// 注销:移除个人信息
export const removeInfo = () => { localStorage.removeItem(USERINFO_KEY) }

修改:store/modules/user.js 模块存|取调用storage:

import { getInfo, setInfo } from '@/utils/storage';

export default {
  namespaced: true,
  state () {
    return {
      // 个人权证相关
      userInfo: getInfo(),        //从localStorage中获取用户信息;
    }
  },
  mutations: {
    //用于组件修改userInfo信息;
    setUserInfo (state, obj) {    //登录成功保存用户信息、保存localStorage
      state.userInfo = obj;
      setInfo(obj)
    }
  },
  actions: {},
  getters: {}
}

在这里插入图片描述

🎉🎉 成功使用:LocalStorage 持久化保存,Vuex;

页面前置导航—守卫💂🏻‍♀

智慧商城项目,大部分页面,游客都可以直接访问: 但,并不是所有业务场景,都支持游客模式;

对于支付页,订单页等,必须是登录的用户才能访问的,游客不能进入该页面,需要做拦截处理;

目标: 如:遇到需要登录才能进行的操作,提示并跳转到登录;

设置项目:路由导航守卫 VueRouter进阶内容

  • 它允许在路由导航发生时执行特定的逻辑,从而控制导航流程;
  • 所有的路由一旦被匹配到: 都会经过全局前置守卫,只有全局前置守卫放行,才会真正解析渲染组件;
router.beforeEach((to, from, next) => {
  // 1. to   往哪里去, 到哪去的路由信息对象  
  // 2. from 从哪里来, 从哪来的路由信息对象
  // 3. next() 是否放行
  //    如果next()调用,就是放行
  //    next(路径) 拦截到某个路径页面
})

优化:router/index.js: 配置全局守卫:访问权限页面时,拦截判断→ 用户是否有登录权证 token

//引入Vuex数据对象;
import store from '@/store'
// 所有的路由在真正被访问到之前(解析渲染对应组件页面前),都会先经过全局前置守卫;
// 只有全局前置守卫next()放行了,才会到达对应的页面;
// 定义数组: 专门存放所有需要权限访问的页面;
const authUrls = ['/pay', '/myorder']
router.beforeEach((to, from, next) => {
  //校验 to.path 是否在 authUrls 中出现过,非权限页面,直接放行;
  if (!authUrls.includes(to.path)) { return next(); }

  // 是权限页面,判断token是否存在
  const token = store.getters.token;
  if (token) { 
    next() 
  } 
  else { 
    next('/login');           //跳转首页;
  }
})

在这里插入图片描述

完结撒花,终于搞定了登录模块、下一篇文章结束这个小Demo项目

代码管理:

本代码已经使用Git进行管理: 公众号回复:Vue项目工程化

在这里插入图片描述

关于Git 版本管理切换可能出现的问题: 代码管理,有时候在操作过程误操作,可能会导致:找不到分支、代码丢失...

git fsck --lost-found
git show be7792e60920d944b772d2154423e958e3a3a646
git reset --hard 1aa0cc91e883597b0769bf36499491b480c7bcb5
#上述命令应该可以解决大部分,分支、代码丢失问题: 2-3命令中索引编码需要根据需求变动)

git fsck --lost-found 命令用来检查Git数据库完整性,并找出任何悬挂丢失 对象,

比如:那些因为提交被重置、删除而不再被引用的文件版本,并返回对应的版本索引:xxxxxxxxxxx 通常是一串长字符;

git show xxxxxxxxxxxxxxxx 显示指定哈希值的提交详情,包括提交信息、作者、日期以及该提交影响的文件的差异;

git reset --hard xxxxxxxxxxxxxxxx 命令将你的工作树、索引(暂存区)以及HEAD指针都重置到指定的提交状态;

删除丢失版本:

删除丢失版本或悬空对象: 通过 git fsck --lost-found 找到的丢失版本或悬空对象,

这些丢失的对象实际上是未被引用的对象,它们在 .git/lost-found 目录下被暂时存放,

以便于恢复误操作删除的数据,如果你确定要删除这些对象,意味着你不再需要它们,可以通过以下步骤:

#首先运行 git fsck --lost-found,这会列出所有悬空的对象
#进入 .git/lost-found 目录,它分为两个子目录: other 和 commit;
cd .git/lost-found		#在尝试删除之前,确保你已经检查过这些文件,确认没有需要恢复的数据;
#删除other和commit目录下的所有文件
rm -rf commit/*
rm -rf other/*
#清理Git数据库: 虽然上述步骤已经删除了文件,但Git的对象数据库中可能还保留着引用计数为0的对象;
git gc --prune=now 		#彻底清理这些不再被引用的对象,这一步会压缩并清理Git仓库
  • 21
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Java.慈祥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值