UNIAPP实战项目笔记54 登录时用state存储用户信息并持久化用户登录和退出登录功能

news2024/11/16 16:51:27

UNIAPP实战项目笔记54 登录时用state存储用户信息并持久化用户登录和退出登录功能

登录信息各个页面同步使用的是state
登录信息的持久化使用的是本地存储
打开APP自动初始化本地存储数据到state中

实际案例图片

  • 登录页面数据渲染

代码 login.vue页面

登录成功后显示的页面

<template>
    <view class="login">
        <swiper vertical="true" style="height: 100vh;">
            <swiper-item>
                <scroll-view>
                    <view class="login-tel">
                        <view class="tel-main">
                            <view class="close" @tap="goBack">
                                <image class="close-img" src="../../static/img/close-bold.png" mode=""></image>
                            </view>
                            <view class="logo">
                                <image class="logo-img" src="../../static/logo.png" mode=""></image>
                            </view>
                            <view class="tel" @tap="goLoginTel">手机号注册</view>
                            <LoginOther></LoginOther>
                            <view class="login-go">
                                <view class="">已有账号,去登录</view>
                                <image src="../../static/img/arrow-down.png" mode=""></image>
                            </view>
                        </view>
                    </view>
                </scroll-view>
            </swiper-item>
            <swiper-item>
                <scroll-view>
                    <view class="login-tel">
                        <view class="tel-main">
                            <view class="close close-center">
                                <view class="" @tap="goBack">
                                    <image class="close-img" src="../../static/img/close-bold.png" mode=""></image>
                                </view>
                                <view class="login-go">
                                    <image class="close-img" src="../../static/img/up.png" mode=""></image>
                                    <view class="">没账号,去注册</view>
                                </view>
                                <view class=""></view>
                            </view>
                            <view class="login-form">
                                <view class="login-user">
                                    <text class='user-text'>账号</text>
                                    <input type="text" v-model="userName" value="" placeholder="请输入手机号/昵称"/>
                                </view>
                                <view class="login-user">
                                    <text class='user-text'>密码</text>
                                    <input type="safe-password" v-model="userPwd" value="" placeholder="6-16位字符"/>
                                </view>
                            </view>
                            <view class="login-quick">
                                <view class="">忘记密码</view>
                                <view class="">免密登录</view>
                            </view>
                            <view class="tel" @tap="submit">登录</view>
                            <view class="reminder">温馨提示,您可以选择免密登录,更加方便</view>
                            <LoginOther></LoginOther>
                        </view>
                    </view>
                </scroll-view>
            </swiper-item>
        </swiper>
        
        
        
    </view>
</template>

<script>
    import $http from '@/common/api/request.js'
    import LoginOther from '@/components/login/login-other.vue'
    import {mapMutations} from 'vuex'
    export default {
        data() {
            return {
                userName:"",
                userPwd:"",
                rules:{
                    userName:{
                        rule:/\S/,
                        msg:"账号不能为空 "
                    },
                    userPwd:{
                        rule:/^[0-9a-zA-Z]{6,16}$/,
                        msg:"密码应该为6-16位字符"
                    }
                }
            };
        },
        components:{
            LoginOther
        },
        methods:{
            ...mapMutations(['login']),
             goBack(){
                 uni.navigateBack();
             },
             submit(){
                 if( !this.validate('userName') ) return ;
                 if( !this.validate('userPwd') ) return ;
                 
                 uni.showLoading({
                     title:"登录中..."
                 });
                 // setTimeout(()=>{
                 //     uni.hideLoading();
                 //     uni.navigateBack();
                 // },2000)
                 
                 $http.request({
                     url:'/login',
                     method:"POST",
                     data:{
                         userName: this.userName,
                         userPwd : this.userPwd
                     }
                 }).then((res)=>{
                     // 保存用户信息
                     this.login(res.data);
                     console.log(res.data);
                     
                     uni.showToast({
                         title:res.msg,
                         icon:"none"
                     })
                     // console.log(res);
                     uni.hideLoading();
                     if(res.success){
                         uni.navigateBack();
                     }
                 }).catch(()=>{
                     uni.showToast({
                         title:'请求失败',
                         icon:'none'
                     })
                 })
             },
             // 判断验证是否符合要求
             validate(key){
                 let bool = true;
                 if( !this.rules[key].rule.test(this[key]) ){
                     uni.showToast({
                         title:this.rules[key].msg,
                         icon:'none'
                     });
                     bool = false;
                     return false;
                 }
                 return bool;
             },
             // 进入手机号注册页面
             goLoginTel(){
                 uni.navigateTo({
                     url:"/pages/login-tel/login-tel"
                 })
             }
        }
    }
</script>

<style lang="scss">
.login-tel{
    width: 100vw;
    height: 100vh;
}
.tel-main{
    padding: 0 20rpx;
}
.close{
    padding: 120rpx 0;
}
.close-img{
    width: 60rpx;
    height: 60rpx;
}
.logo{
    padding: 0 100rpx;
    padding-bottom: 100rpx;
    display: flex;
    justify-content: center;
    
}
.logo-img{
    width: 200rpx;
    height: 200rpx;
}
.tel{
    width: 100%;
    height: 80rpx;
    line-height: 80rpx;
    text-align: center;
    color: #fff;
    background-color: #40bde8;
    border-radius: 40rpx;
}


.login-go{
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
}
.login-go image{
    width: 60rpx;
    height: 60rpx;
}

// 第二屏
.close-center{
    display: flex;
}
.close-center >view{
    flex: 1;
}
.login-form{
    padding-top: 100rpx;
}
.login-user{
    font-size: 40rpx;
    padding: 10rpx 0 ;
    display: flex;
    align-items: center;
    border-bottom: 2rpx solid #f7f7f7;
}
.user-text{
    padding-right: 10rpx;
}
.login-quick{
    display: flex;
    padding: 20rpx 0;
    justify-content: space-between;
}
.reminder{
    color: #ccc;
    font-size: 32rpx;
    padding: 20rpx 0;
    text-align: center;
}
</style>

代码 my.vue页面

设置功能里面有退出按钮,通过调用state中的outLogin方法来实现退出功能

<template>
    <view class="my">
        <!-- 头部 -->
        <view class="my-header">
            <view class="header-main">
                <view class="header-config" @tap="goConfig">
                    <image class="config-img" src="../../static/tabbar/list.png" mode=""></image>
                </view>
                <view class="header-logo">
                    <image class="logo-img" :src="loginStatus ? userInfo.imgUrl :'../../static/tabbar/mySelected.png'" mode=""></image>
                    <view class="logo-name" @tap="goLogin">{{loginStatus ? userInfo.nickName : '用户昵称'}}</view>
                </view>
            </view>
        </view>
        <!-- 我的订单 -->
        <view class="order">
            <view class="order-title" @tap="goOrder">
                <view class="">我的订单</view>
                <view class="">全部订单 > </view>
            </view>
            <view class="order-list">
                <view class="order-item">
                    <image class="order-img" src="../../static/logo.png" mode=""></image>
                    <view class="">待付款</view>
                </view>
                <view class="order-item">
                    <image class="order-img" src="../../static/logo.png" mode=""></image>
                    <view class="">待付款</view>
                </view>
                <view class="order-item">
                    <image class="order-img" src="../../static/logo.png" mode=""></image>
                    <view class="">待付款</view>
                </view>
                <view class="order-item">
                    <image class="order-img" src="../../static/logo.png" mode=""></image>
                    <view class="">待付款</view>
                </view>
                <view class="order-item">
                    <image class="order-img" src="../../static/logo.png" mode=""></image>
                    <view class="" @tap="qianzi">待付款1</view>
                </view>
            </view>
            <!-- 内容列表 -->
            <view class="my-content">
                <view class="my-content-item" v-for="(item,index) in 6">
                    <view class="">
                        我的收藏
                    </view>
                    <view class="">
                        >
                    </view>
                </view>
            </view>
        </view>
    </view>
</template>

<script>
    import {mapState} from 'vuex'
    export default {
        data() {
            return {
                
            }
        },
        computed:{
            ...mapState({
                loginStatus:state=>state.user.loginStatus,
                userInfo:state=>state.user.userInfo
            })
        },
        methods: {
            goConfig(){
                uni.navigateTo({
                    url:'../my-config/my-config'
                })
            },
            goOrder(){
                uni.navigateTo({
                    url:'../my-order/my-order'
                })
            },
            qianzi(){
                uni.navigateTo({
                    url:'../qianzi/qianzi'
                })
            },
            goLogin(){
                uni.navigateTo({
                    url:'/pages/login/login'
                })
            }
        }
    }
</script>

<style lang="scss">
.my-header{
    background-color: #eee;
    width: 100%;
    height: 400rpx;
}
.header-main{
    position:relative;
    top: 120rpx;
}
.header-config{
    position: absolute;
    left: 20rpx;
}
.header-logo{
    position: absolute;
    left:50%;
    margin-left:-60rpx;
    width: 120rpx;
}
.config-img{
    width: 40rpx;
    height: 40rpx;
}
.logo-img{
    width: 120rpx;
    height: 120rpx;
    border:2rpx solid #ccc;
    border-radius: 50%;
    background-color: #FFFFFF;
}
.logo-name{
    color: #FFFFFF;
    font-size: 30rpx;
    font-weight: bold;
    text-align: center;
}
.order-title{
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 20rpx;
}
.order-list{
    padding:20rpx;
    display: flex;
}
.order-item{
    flex:1;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
}
.order-img{
    width: 80rpx;
    height: 80rpx;
}
.my-content{
    margin:20rpx 0;
    padding: 0 20rpx;
}
.my-content-item{
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 20rpx 0;
    border-bottom: 2px solid #ccc;
}
</style>

代码 my-config.vue页面

退出功能具体实现

<template>
    <view class="my-config">
        
        <view class="config-item" @tap="goPathList">
            <view class="">地址管理</view>
            <view class=""> > </view>
        </view>        
        
        <view class="config-item" v-for="(item,index) in 5">
            <view class="">地址管理</view>
            <view class=""> > </view>
        </view>
        
        <view class="my-exit" @tap="outLogin">
            退出
        </view>
        
    </view>
</template>

<script>
    import {mapMutations} from 'vuex'
    export default {
        data() {
            return {
                
            };
        },
        methods:{
            ...mapMutations(['loginOut']),
            goPathList(){
                uni.navigateTo({
                    url:'../my-path-list/my-path-list'
                })
            },
            outLogin(){
                uni.showToast({
                    title:"退出成功!",
                    icon:'none'
                });
                this.loginOut();
                uni.switchTab({
                    url:"/pages/index/index"
                })
            }
        }
    }
</script>

<style lang="scss">
.config-item{
    display: flex;
    justify-content: space-between;
    padding: 20rpx;
    border-bottom: 2rpx solid #ccc;
}
.my-exit{
    background-color: #49bdfb;
    width: 100%;
    line-height: 80rpx;
    color: #FFFFFF;
    text-align: center;
}
</style>

代码 /store/modules/user.js

user用到的state

export default{
    state:{
        // 登录状态
        loginStatus:false,
        // token
        token:null,
        // 用户信息 昵称头像等
        userInfo:{}
    },
    getters:{

    },
    mutations:{
        // 一旦进入app,就需要执行这个方法把用户信息读出来,放到App.vue的onLaunch中触发
        initUser(state){
            let userInfo = uni.getStorageSync('userInfo');
            if( userInfo ){
                userInfo = JSON.parse(userInfo);
                state.userInfo = userInfo;
                state.loginStatus = true;
                state.token = userInfo.token;
            }
        },
        
        // 登录后保存用户信息
        login(state,userInfo){
            state.userInfo = userInfo;
            state.loginStatus = true;
            state.token = userInfo.token;
            
            // 持久化存储 -- 把对象转换成字符串
            uni.setStorageSync('userInfo',JSON.stringify(userInfo));
        },
        
        // 退出登录
        loginOut(state){
            state.userInfo = {};
            state.loginStatus = false;
            state.token = null;
            // 删除本地持久化存储
            uni.removeStorageSync('userInfo');
        }
    },
    actions:{
        
    }
}

代码 /store/index.js

将 user.js引入到 state

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex);

// 购物车
import cart from './modules/cart.js'
// 地址管理
import path from './modules/path.js'
// 用户
import user from './modules/user.js'

export default new Vuex.Store({
    modules:{
        cart,
        path,
        user
    }
})

代码 /App.js

进入APP持久化数据获取

<script>
	export default {
		onLaunch: function() {
            // 打开APP自动触发的事件
            this.$store.commit('initUser');
			console.log('App Launch')
		},
		onShow: function() {
			console.log('App Show')
		},
		onHide: function() {
			console.log('App Hide')
		}
	}
</script>

<style>
	/*每个页面公共css */
    @import '@/common/uni.css';
    @import '@/common/common.css';
    @import '@/static/iconfont/iconfont.css';
</style>

目录结构

前端目录结构

  • manifest.json 配置文件: appid、logo…

  • pages.json 配置文件: 导航、 tabbar、 路由

  • main.js vue初始化入口文件

  • App.vue 全局配置:样式、全局监视

  • static 静态资源:图片、字体图标

  • page 页面

    • index
      • index.vue
    • list
      • list.vue
    • my
      • my.vue
    • my-config
      • my-config.vue
    • my-config
      • my-config.vue
    • my-add-path
      • my-add-path.vue
    • my-path-list
      • my-path-list.vue
    • search
      • search.vue
    • search-list
      • search-list.vue
    • shopcart
      • shopcart.vue
    • details
      • details.vue
    • my-order
      • my-order.vue
    • confirm-order
      • confirm-order.vue
    • payment
      • payment.vue
    • payment-success
      • payment-success.vue
    • login
      • login.vue
    • login-tel
      • login-tel.vue
    • login-code
      • login-code.vue
  • components 组件

    • index
      • Banner.vue
      • Hot.vue
      • Icons.vue
      • indexSwiper.vue
      • Recommend.vue
      • Shop.vue
    • common
      • Card.vue
      • Commondity.vue
      • CommondityList.vue
      • Line.vue
      • ShopList.vue
    • order
      • order-list.vue
    • uni
      • uni-number-box
        • uni-number-box.vue
      • uni-icons
        • uni-icons.vue
      • uni-nav-bar
        • uni-nav-bar.vue
      • mpvue-citypicker
        • mpvueCityPicker.vue
  • common 公共文件:全局css文件 || 全局js文件

    • api
      • request.js
    • common.css
    • uni.css
  • store vuex状态机文件

    • modules
      • cart.js
      • path.js
      • user.js
    • index.js

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/96871.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

论文阅读 - Social Bot-Aware Graph Neural Network for Early Rumor Detection - CCF B

目录 摘要&#xff1a; 1 绪论 2 问题定义 3 SBAG模型 3.1社交机器人检测 3.2 机器人感知图神经网络 3.2.1基于GCN的用户发布 3.2.2 基于GAT的用户交互 3.2.3文本编码器 3.2.4 输出层 3.3 训练 4 实验 4.1 数据集 4.2 实验设置 4.3 基线 4.4 实验结果 4.4.1 谣言…

对时间序列数据(牛仔裤销售数据集)进行LSTM预测(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 LSTM模型的一个常见用途是对长时间序列数据进行学习预测&#xff0c;例如得到了某商品前一年的日销量数据&#xff0c;我们可以…

【GPU】Nvidia CUDA 编程高级教程——利用蒙特卡罗法求解近似值(NVSHMEM)

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…

MyBatis + SQL Server Using Table-Valued Parameters

一、实现原理 参考文档 Using table-valued parametersSystem requirements for the JDBC driverMicrosoft JDBC Driver for SQL Server1、微软官方封装了 JDBC 驱动 jar 包&#xff0c;提供 SQLServerDataTable 类&#xff1b; 2、Mybatis 官方提供自定义类型处理接口 TypeHa…

Python学习笔记-Pygame

目录 一、Pygame概述 1.安装Pyganme 2.Pygame常用模块介绍 2.1 display模块常用方法 2.2 pygame.event模块常用方法 2.3 Surface对象的常用方法 记述关于Pyganme开发的基本知识。 一、Pygame概述 Pygame是跨平台的python模块&#xff0c;转为电子游戏设计&#xff08;包…

Vue打包后的不同版本解析

vue源码打包版本 这里选取我们开发中常见的几个版本进行说明。 1、vue(.runtime).global(.prod).js 在html页面中通过 <script src“...”> 标签直接使用。通过CDN引入和npm下载的Vue就是这个版本。会暴露一个全局的Vue来使用。&#xff08;.runtime&#xff09;和&…

2022年12月python的字符串常用操作

字符串在整整个开发的过程中&#xff0c;使用频率相对来说是较高的。 在此总结几个字符串的常用操作&#xff0c; 字符串的操作&#xff0c;转换后即生成为新字符串 【长度统计 切片&#xff1a; 【 根据索引进行切片str[开始索引:结束索引:步长] 根据指定标识符进行切片str.sp…

【码极客精讲】桶排序

桶排序 (Bucket sort)或所谓的箱排序&#xff0c;是一个排序算法&#xff0c;工作的原理是将数组分到有限数量的桶子里。每个桶子再个别排序&#xff08;有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序&#xff09;。桶排序是鸽巢排序的一种归纳结果。当要被排…

【硬币识别】形态学硬币计数【含Matlab源码 683期】

⛄一、硬币图像识别简介 本设计为硬币图像识别统计装置&#xff0c;通过数码相机获取平铺无重叠堆积的硬币的图像&#xff0c;并通过Matlab工具处理后统计硬币的数目。 1 图像格式转换 取的图像格式为RGB彩色图像&#xff0c;需要先将其转换为8位256级的灰度图像。本程序采用…

SAP Gateway 里的 REST 概念

SAP Gateway 有助于轻松配置和使用 SAP Business Suite 系统的业务逻辑和内容&#xff0c;用于移动和 Web 应用程序。它降低了访问 SAP 数据所需的复杂性和技能组合&#xff0c;从而消除了部署障碍。使用简单的界面有助于缩短开发时间。 SAP Gateway 使以人为本的应用程序能够…

【笔记:模拟CMOS集成电路】MOS特性仿真分析

【笔记&#xff1a;模拟CMOS集成电路】MOS特性仿真分析前言一、电路图二、电路仿真&#xff08;1&#xff09;Ids与Vds的关系仿真仿真结果仿真结果分析&#xff08;2&#xff09;Ids与Vgs的关系仿真仿真结果仿真结果分析前言 本文为本人学习模拟集成电路相关知识的的学习笔记&a…

USB接口WIFI(MT7601芯片)的驱动源码移植过程详解(驱动源码编译、wpa_supplicant工具交叉编译、文件系统移植)

1、MT7601的移植步骤 (1)确认你的WT7601网卡硬件是正常的&#xff1b; (2)修改驱动源码&#xff0c;依赖内核源码树编译并加载&#xff1b; (3)交叉编译wpa_supplicant工具&#xff0c;移植到根文件系统里&#xff1b; (4)添加驱动和wpa_supplicant工具依赖的配置文件&#xff…

2022 年时间序列分析最顶流的 Python 库

时间序列分析是一种强大的工具&#xff0c;可用于从数据中提取有价值的信息并对未来事件进行预测。它可用于识别趋势、季节性模式和变量之间的其他关系。时间序列分析还可用于预测未来事件&#xff0c;例如销售、需求或价格变动。 如果你在 Python 中处理时间序列数据&#xf…

数据库实验三:完整性语言实验

实验三 完整性语言实验 实验 3.1 实体完整性实验 1.实验目的 ​ 掌握实体完整性的定义和维护方法。 2.实验内容和要求 ​ 定义实体完整性&#xff0c;删除实体完整性。能够写出两种方式定义实体完整性的SQL语句&#xff1b;创建表时定义实体完整性、创建表后定义实体完整性…

C++ Reference: Standard C++ Library reference: Containers: map: map: key_comp

C官网参考链接&#xff1a;https://cplusplus.com/reference/map/map/key_comp/ 公有成员函数 <map> std::map::key_comp key_compare key_comp() const;返回键比较对象 返回容器用于比较键的比较对象的副本。map对象的比较对象在构造&#xff08;construction&#xff…

kubernetes 挂载传播

kubernetes 挂载传播 kubernetes 的 mountPropagation 翻译成中文就是挂载传播。挂载传播提供了共享卷挂载的能力, 它允许在同一个 Pod, 甚至同一个节点内, 在多个容器之间共享卷的挂载。 说白了就是在容器或 host 内的挂载目录中 再 mount 了一个别的挂载。 kubernetes 中 卷…

第18章 条件概率

第18章 条件概率 18.1蒙特霍尔困惑 对于上一章的三个门的问题&#xff0c;有一个漏洞。假设参赛者选择门A且门B后有一只山羊&#xff0c;刚好产生3个结果&#xff1a; 以上结果出现的概率分别是1/18,1/18,1/9。 在这些结果中&#xff0c;只有最后一个结果(C,A,B)&#xff0c…

Redis常见面试题(三)

目录 1、Redis String值最大存储多少? 2、Redis事务有什么用? 3、Redis事务相关的命令有哪几个? 4、Redis事务是原子性的吗? 5、Redis持久化有什么用? 6、Redis有哪几种持久化方式? 7、Redis持久化方式如何选择? 8、如何保证Redis中的数据都是热点数据? 9、Red…

vue前后端分离项目打包成app,部署成移动端

将vue项目打包成app,在手机上运行。 1. vue打包 npm run build 先将vue的前端项目打包成dist文件夹 2. 安装hbuilderX Hbuilder官网地址 3. hbuilderX 1&#xff09;新建项目 我是vue的&#xff0c;所以直接选择的h5app&#xff0c;然后起个名字&#xff0c;选择路径。 2…

微服务实用篇6-分布式搜索elasticsearch篇2

今天我们继续学习分布式搜索引擎elasticsearch&#xff0c;今天主要学习四个模块&#xff0c;分别为DSL查询文档&#xff0c;搜索结果处理&#xff0c;RestClient查询文档&#xff0c;还有最好演示一个旅游案例。下面开始今天的学习吧。 目录 一、DSL查询文档 1.1、DSL查询分…