项目初始化+登录(办鹿)

收藏

一、为什么要拿uniapp去做这个微信小程序 (为什么不用原生小程序做?)

方便日后扩展其他端


二、蓝湖设计图


https://lanhuapp.com/link/#/invite?sid=lXJcIh1a

分享人: 41238206

蓝湖团队: 小鹿线团队的团队

相关项目: 办鹿

链接有效期: 20230223~20230309


三、前期项目搭建 


3.1 项目创建(vue2版本)

3.2 ui组件的引入==>方便开发


引入方式:2形式(1. npm下载 2. 直接导入到项目中)


***引入方式区别:


npm下载的形式,在h5端没问题,在其他端可能无效(微信小程序)

直接导入到项目的是100%有效


a>插件市场导入


https://ext.dcloud.net.cn/plugin?id=1593


b> main.js



			// main.js
			import uView from '@/uni_modules/uview-ui'
			Vue.use(uView)

c> uni.scss



			/* uni.scss */		
			@import '@/uni_modules/uview-ui/theme.scss';

d> pages.json



			{
				// 如果您是通过uni_modules形式引入uView,可以忽略此配置
				"easycom": {
					"^u-(.*)": "@/uni_modules/uview-ui/components/u-$1/u-$1.vue"
				},
				
				// 此为本身已有的内容
				"pages": [
					// ......
				]
			}

3.3 请求二次封装,api解耦 ==》项目请求数据方便更好维护和管理


// 此vm参数为页面的实例,可以通过它引用vuex中的变量
module.exports = (vm) => {
    // 初始化请求配置
    uni.$u.http.setConfig((config) => {
        /* config 为默认全局配置*/
		// #ifndef H5
		   config.baseURL = 'http://uat.banlu.xuexiluxian.cn'; /* 根域名 */
		// #endif
        return config
    })
	
	// 请求拦截
	uni.$u.http.interceptors.request.use((config) => { // 可使用async await 做异步操作
	 //    // 初始化请求拦截器时,会执行此方法,此时data为undefined,赋予默认{}
	 //    config.data = config.data || {}
		// // 根据custom参数中配置的是否需要token,添加对应的请求头
		// if(config?.custom?.auth) {
		// 	// 可以在此通过vm引用vuex中的变量,具体值在vm.$store.state中
		// 	config.header.token = vm.$store.state.userInfo.token
		// }
	    return config 
	}, config => { // 可使用async await 做异步操作
	    return Promise.reject(config)
	})
	
	// 响应拦截
	uni.$u.http.interceptors.response.use((response) => { /* 对响应成功做点什么 可使用async await 做异步操作*/
		const data = response.data
		
		return data === undefined ? {} : data
	}, (response) => { 
		// 对响应错误做点什么 (statusCode !== 200)
		return Promise.reject(response)
	})
}
	const http = uni.$u.http

// // post请求,获取菜单
// export const postMenu = (data) => http.post('/ebapi/public_api/index', data)

// // get请求,获取菜单,注意:get请求的配置等,都在第二个参数中,详见前面解释
// export const getMenu = (data) => http.get('/ebapi/public_api/index', {params:data})

3.4 工具类、混入、状态管理



四、vue和nvue文件的区别


uniapp的优势:一套代码生成多端(要写大量的条件编译)

uniapp的优点:app端性能不好


***怎么解决这个性能不好的问题:.nvue文件来解决(nvue文件是为了来做app端而生的)


五、工作流 

1. appid ===》 公司给你


办鹿:wxc82730a0fc15e28a


2. 自己的开发者身份


***把自己的微信号发给助教老师


3. 接口文档


网址:http://doc.xuexiluxian.cn/web/#/

帐号:testapi

密码:123456


六、关于跨域问题


解决方式:

1.前端解决 


其他的项目:jsonp...

vue的项目:代理

微信小程序:不校验URL,但是项目上线就必须交验url(所以要在后台配置合法域名)

h5端

//只是在h5端生效,在小程序端是不生效端
module.exports = {
	devServer:{
		proxy:{
			'/':{
				target:'http://uat.banlu.xuexiluxian.cn',
				changeOrigin:true
			}
		}
	}
}

需要将request.js修改

 uni.$u.http.setConfig((config) => {
        /* config 为默认全局配置*/
		// #ifndef H5
		   config.baseURL = 'http://uat.banlu.xuexiluxian.cn'; /* 根域名 */
		// #endif
        return config
    })
	

2.后端解决

tabar https://uniapp.dcloud.net.cn/collocation/pages.html#tabbar 

{
	"easycom": {
		"^u-(.*)": "@/uni_modules/uview-ui/components/u-$1/u-$1.vue"
	},
	"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
		{
			"path": "pages/tabs/index",
			"style": {
				"navigationBarTitleText": "uni-app"
			}
		},
		{
			"path": "pages/tabs/list",
			"style": {
				"navigationBarTitleText": "uni-app"
			}
		},
		{
			"path": "pages/tabs/me",
			"style": {
					"navigationStyle": "custom"//自定义头部
				}

		}
	],
	"tabBar": {
		"color": "#7A7E83",
		"selectedColor": "#3cc51f",
		"borderStyle": "black",
		"backgroundColor": "#ffffff",
		"list": [{
			"pagePath": "pages/tabs/index",
			"text": "推荐"
		}, {
			"pagePath": "pages/tabs/list",
			"text": "分类"
		},
		{
			"pagePath": "pages/tabs/me",
			"text": "我的"
		}]
	},
	"globalStyle": {
		"navigationBarTextStyle": "black",
		"navigationBarTitleText": "uni-app",
		"navigationBarBackgroundColor": "#F8F8F8",
		"backgroundColor": "#F8F8F8"
	},
	"uniIdRouter": {}
}

七、uniapp条件编译


是什么:针对于不同端执行不同代码

你在什么时候用过:在处理小程序和h5请求方便


八、微信一键登录流程


***前提要有:appid和开发者身份,要不然测试不了


1. 点击 【微信一键登录】按钮(说白了就是随便一个按钮来触发方法)

2. 调用uniapp提供的api:uni.getUserProfile//微信小程序也提供 https://uniapp.dcloud.net.cn/api/plugins/login.html 


uni.getUserProfile是什么:获取用户信息。每次请求都会弹出授权窗口,用户同意后返回 userInfo。



3. 调用uni.login方法,会获取用户的code编码


这个code编码需要传递给后端,其实就是来看看这个用户在当前小程序之前有没有注册过

               code码是字符串


4. 如果没有注册过,调用后端接口:wechatRegister(去注册),需要传递的数据有


unionId 是 string 开放平台ID,如果后端未返回则传OPENID

openId 是 string OPENID

sessionKey 是 string SESSION KEY

signature 是 string 签名

rawData 是 string 原始数据

encryptedData 是 string 加密数据

iv 是 string 偏移量

具体如下:

    import { loginByWechat , wechatRegister } from '@/utils/api/login.js'
    export default{
	methods:{
		login(){
			uni.1({
				desc:'登录后同步数据',
				success( ures ){
					console.log( 'getUserProfile',ures  )
					// ures是用来获取用户信息的
					uni.login({
						success( lres ){
							//通过这个code来判断,这个用户在这个小程序有没有注册过[之前有没有登录过]
							let params = {
								code:lres.code
							}
							loginByWechat(params).then(res=>{
								console.log('后端接口返回',res )
								if( res.code == '60003' ){
									//注册微信用户
									wechatRegister({
										unionId:res.data.unionId ? res.data.unionId : res.data.openid,
										openId:res.data.openid,
										sessionKey:res.data.sessionKey,
										signature:ures.signature,
										rawData:ures.rawData,
										encryptedData:ures.encryptedData,
										iv:ures.iv
									}).then(resdata=>{
										console.log( 11 , resdata )
										//注册完成后存储token
										//是否绑定手机号
									})
								}else{
									//也可以不绑定
								}
							})
							
						}
					})				
				}
			})				
		}
	}
}


5. 注册功能后后端会给前端返回token


5.1 前端要把token存储起来 ==> 本地存储中 https://uniapp.dcloud.net.cn/api/storage/storage.html#setstorage 

***注意:在微信小程序是没有cookie的

***注意:在uniapp中没有原生localStorage要用uni.setStorage/getStorage

uni.setStorage({
	key: 'storage_key',
	data: 'hello',
	success: function () {
		console.log('success');
	}
});
uni.getStorage({
	key: 'storage_key',
	success: function (res) {
		console.log(res.data);
	}
});

那么具体改为

<template>
	<view>
		<button @click='login'>微信登录</button>
	</view>
</template>

<script>
import { loginByWechat , wechatRegister } from '@/utils/api/login.js'
export default{
	methods:{
		//点击登录
		login(){
			let that = this;
			uni.getUserProfile({
				desc:'登录后同步数据',
				success( ures ){
					uni.login({
						success( lres ){
							//通过这个code来判断,这个用户在这个小程序有没有注册过[之前有没有登录过]
							let params = {
								code:lres.code
							}
							loginByWechat(params).then(res=>{
								//当前微信用户未注册 ==》 60003
								if( res.code == '60003' ){
									let params = {
										unionId:res.data.unionId ? res.data.unionId : res.data.openid,
										openId:res.data.openid,
										sessionKey:res.data.sessionKey,
										signature:ures.signature,
										rawData:ures.rawData,
										encryptedData:ures.encryptedData,
										iv:ures.iv
									};
									//那么就去注册
									that.register(params);
								}else if(res.code=='200'){
								//之前注册过,检验是否绑定过是手机号
								that.isMobile(res.data);
								}
							})
							
						}
					})
				}
			})
		},
		//注册微信用户
		register( params ){
			wechatRegister(params).then(res=>{
				if( res.code == '200' ){
					this.isMobile( res.data );
				}else{
					//失败的弹出信息
				}
			})
		},
		//登录
		isMobile( data ){
		
			//存储token
			uni.setStorage({
				key:'token',
				data:data.token
			})
			
			//判断用户有没有绑定过手机号
			if( !data.member.mobile ){
				uni.showModal({
					title:'提示信息',
					confirmText:'去完善',
					content:'根据国家规定,需要绑定手机号',
					success( res ){
						if( res.confirm ){
							uni.navigateTo({
								url:'/pages/login/bindPhone'
							})
						}else{//取消
							
						}
					}
				})
			}
			
		}
	}
}
</script>

<style>
</style>

九、当给你一个表单,你会处理那些问题?


1. 检验表单中输入的内容是否合规 从而也防止了 sql注入

uview中的纯数字输入键盘

2. 提交表单的时候,明文要加密(aes) uview封装的纯数字

	<input class="uni-input" type="number" placeholder="这是一个数字输入框"  v-model='form.phone'/>

a> 下载aes

			npm install crypto-js -S

b> aes中配置了什么?你怎么配置的?


秘钥、偏移量、加密方法、解密方法

// 引入AES源码js


const CryptoJS = require('crypto-js')


// 默认的KEY与IV如果没有给||后端接口会给

// 秘钥:bGvnMc62sh5RV6zP

// 偏移量:1eZ43DLcYtV2xb3Y


const CryptoJS = require('crypto-js')
const key = CryptoJS.enc.Utf8.parse('bGvnMc62sh5RV6zP') // 十六位十六进制数作为密钥
const iv = CryptoJS.enc.Utf8.parse('1eZ43DLcYtV2xb3Y') // 十六位十六进制数作为密钥偏移量

// 解密方法
export function Decrypt(word) {
    const encryptedHexStr = CryptoJS.enc.Hex.parse(word)
    const srcs = CryptoJS.enc.Base64.stringify(encryptedHexStr)
    const decrypt = CryptoJS.AES.decrypt(srcs, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 })
    const decryptedStr = decrypt.toString(CryptoJS.enc.Utf8)
    return decryptedStr.toString()
}

// 加密方法
export function Encrypt(word) {
    const srcs = CryptoJS.enc.Utf8.parse(word)
    const encrypted = CryptoJS.AES.encrypt(srcs, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 })
    return encrypted.ciphertext.toString().toUpperCase()
}

//绑定是手机号的页面

<template>
	<view>
		<button @click='login'>微信一键登录</button>
	</view>
</template>

<script>
	import {
		loginByWechat,
		wechatRegister
	} from '@/untils/api/login.js';
	import {
		mapState,
		mapActions,
		mapMutations
	} from 'vuex';
	import {
		toArray
	} from 'xe-utils';

	export default {
		methods: {
			...mapMutations(['setToken']),
			...mapActions(['getUserInfo']),
			async login() {
				let that = this
				uni.getUserProfile({
					desc: 'denglu',
					success: (ures) => {
						uni.login({
							success(lres) {
								let params = {
									code: lres.code,
									// code 是用来判断用户在这个小程序有没有注册过(之前有没有登陆过)
								}
								loginByWechat(params).then(res => {
									// console.log(res)
									if (res.code == '60003') {
										// 说明用户还没有注册需要注册
										console.log('还没有注册过')
										let params = {
											unionId: res.data.unionId ? res.data
												.unionId : res.data.openid,
											openId: res.data.openid,
											sessionKey: res.data.sessionKey,
											signature: ures.signature,
											rawData: ures.rawData,
											encryptedData: ures.encryptedData,
											iv: ures.iv
										}
										return that.register(params)
									} else if (res.code == '200') {
										// 之前注册过,检验是否绑定过手机号
										that.mobile(res.data)
									}
								})
							}
						})
					}
				})
			},
			// 注册微信用户
			register(params) {
				wechatRegister(params).then(resdata => {
					if (resdata.code == '200') {
						// 说明微信注册成功
						this.mobile(resdata.data)
						return
					} else {
						// 失败则弹出信息
						console.log('注册失败')
					}
				})
			},
			// 检验使用之前是否绑定过手机号
			async mobile(data) {
				// 存储token
				this.setToken(data.token)
				if (!data.member.mobile) {
					this.isMobile()
				} else {
					await this.getUserInfo()
					// 如果绑定过手机号,返回上一页
					uni.navigateBack()
				}
			},
			async isMobile(data) {
				let that = this
				uni.showModal({
					title: '去完善',
					content: '根据国家规定需要绑定手机号',
					async success(res) {
						if (res.confirm) {
							uni.navigateTo({
								url: '/login/bindPhone'
							})
						} else {
							await that.getUserInfo()
							// 如果绑定过手机号,返回上一页
							uni.navigateBack()
						}
					}
				});

			}
		}
	}
</script>

<style>

</style>

在store中有存储token和获取用户信息的方法(持久化存储)在index.ts这个页面中

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

//引入vuex持久化存储插件
import persistedstate from 'vuex-persistedstate'

Vue.use(Vuex);

import user from './modules/user'
const store = new Vuex.Store({
	modules: {
		user
	},
	plugins: [
		persistedstate({
			storage: {
				getItem: key => uni.getStorageSync(key),
				setItem: (key, value) => uni.setStorageSync(key, value),
				removeItem: key => uni.removeStorageSync(key)
			}
		})
	]
})
export default store

/modules/user

import {
	userInfo
} from '@/untils/api/login.js';
export default {
	state: {
		token: '',
		info: {
			status: false
		}
	},
	mutations: {
		setToken(state, value) {
			state.token = value;
		},
		getInfo(state, res) {
			state.info = Object.assign({
				status: true
			}, res.data);
		}
	},
	actions: {
		async getUserInfo({
			commit
		}) {
			let res = await userInfo();
			if (res.code == '200') commit('getInfo', res);
		}
	}
}

绑定的手机号的页面

<template>
	<view class="">
		<input class="uni-input" type="number" placeholder="手机号" v-model="form.phone" />
		<input type="text" placeholder="验证码" v-model="form.code">
		<button @click="sendCode">{{codeText}}</button>
		<button @click="bindPhone">确定</button>
	</view>
</template>

<script>
	import {
		updateMobile,
		sendMessage
	} from '@/untils/api/login.js';
	import {
		Encrypt
	} from '@/untils/aes.js';
	import {
		mapActions
	} from 'vuex'
	export default {
		data() {
			return {
				form: {
					phone: '',
					code: ''
				},
				time: 10,
				codeText: '获取手机验证码'
			}
		},
		methods: {
			...mapActions(['getUserInfo']),
			// 发送短信验证码
			async sendCode() {
				let that = this;
				let reg = /^1[2-9]\d{9}$/;
				// 判断用户输入的手机号格式对不对
				if (reg.test(this.form.phone)) {
					let res = await sendMessage({
						mobile: Encrypt(this.form.phone),
						key: 'MODIFY_MOBILE'
					})
					// console.log(res)
					// 说明手机号发送是成功的
					if (res.code == '200') {
						uni.showToast({
							title: '验证码发送成功',
							icon: 'none'
						})
						let time = this.time;
						let timer = setInterval(function() {
							if (time == 0) {
								clearInterval(timer)
								that.codeText = '重新获取手机验证码'
							} else {
								that.codeText = `还剩下${time}秒`;
								time--
							}
						}, 1000)
					}
				} else {
					uni.showToast({
						title: '请输入正确的11位手机号',
						icon: 'none'
					})
				}
			},
			//确定绑定
			async bindPhone() {
				let res = await updateMobile({
					mobile: Encrypt(this.form.phone),
					captcha: this.form.code
				})
				//绑定成功,跳转到首页
				if (res.code == '200') {
					//获取用户的信息
					await this.getUserInfo();
					//跳转页面
					uni.switchTab({
						url: "/pages/tabs/me"
					})
				} else {
					uni.showToast({
						title: '该手机号已被绑定'
					})
				}
			}
		}
	}
</script>

反正不管绑定不绑定手机号他们都会跳转到上一页

接口联调

问问后端那个是是哪个的接口

十、性能问题


10.1 你做过哪些性能优化



a> 冻结对象 : Object.freeze


因为如果vue直接复制给data属性值,会走observer,使用Object.freeze冻结可以提升效率


****这个对象以后不能修改了



10.2 加入后端一次性给你10W条数据,你如何把数据放在页面


虚拟列表

  swiper   https://uniapp.dcloud.net.cn/component/swiper.html 


十一、2月24作业


1. 项目登录做了,多去看看逻辑上哪里有问题?

2. 如何把表格的数据放在页面上(导入)

搜索vue把表格放在页面

3. 如何实现架构图

vue组织架构图

4. 数据重构 ex : 扁平化数据转换成多叉树 ...

import XEUtils from 'xe-utils';

评论(

您还未登录,请先去登录
表情
查看更多

相关作者

  • 获取点赞0
  • 文章阅读量264

相关文章

联系小鹿线

咨询老师

咨询老师

扫码下载APP