0


购优偿WebApp开发整理

购优偿WebApp

项目实机展示

欢迎/注册/登录页

在这里插入图片描述

主页/加购物车/设置地址

在这里插入图片描述

地址增删改

在这里插入图片描述

提交订单/所有订单列表

在这里插入图片描述

其他(我的,地图,个人信息及获取手机联系人,视频及弹幕,分类页)

在这里插入图片描述

在这里插入图片描述

项目流程简要记录

知识点:
1. 选项式/组合式的父子组件互相引入;函数式(组合式)编程没有this;
2. 推导类型/显示类型
3. 定义计算属性/监视属性
4. 全局的接口;vite-env.ts ; 
    1. 首先全局处理 declare module '*.vue'{} //typescript语法
    2. Interface User{}
1. swagger 接口网站
1. 开发的APP类型
     1. WebApp -- 在手机浏览器上运行的app
    2. HybirdApp -- 混合app
            1. Cordova
        2. Hbuilder 和 ApiCloud 以上两类开发模式都是有一个原生壳,然后编写html、js、css开发一个项目,运行在壳里边
        3. ReactNative、Weex -- 编写类似于小程序的方式来实现代码编写和开发(类似鸿蒙)
            4. flutter
      3. NativeApp -- 纯原生开发;Android是用的是Java、koltin;iOS Object-c、swift
2. 架构分析
        |—— project
            |—— src
                |—— main.ts 入口文件
                |—— pages
                    |—— index.vue 项目启动文件
                    |—— login
                        |—— index.vue 项目登陆页面
                |—— router
                    |—— index.ts 路由的主要注册文件
                    |—— interceptor.ts 路由拦截器
                |—— store
                    |—— index.ts 实现状态管理器的管理
                |—— style
                    |—— index.less 项目的全局样式
                    |—— common.less 全局定义的变量、方法
                |—— images 项目的图片目录
                |—— config 项目的常量定义
                |—— apis 实现接口请求的方法
                |—— components 实现全局组件
知识点: 
1. 安装vite框架/依赖
    1. yarn create vite
    2. cd mingcheng
    3. yarn install
    4. yarn dev
2. 处理框架 路由以及挂载
    1. 创建删除文件
    2. vue-router插件的下载引入
        router/index.ts 中import{createRouter} from 'vue-router';
        main.ts 中vue2/vue3 的挂载与注入路由对象
3. 创建基础的页面
    1. pages文件下创建;
    2. routes路径的写入;
    3. component Login/home的组件书写;
    4. 渲染到pages/index.vue 页面;
4. 拦截器

安装准备

  1. node -v 18.16.1
  2. 下载/运行/删除不必要
  3. 创建pages/index.vue;
  4. 创建src/main.ts;- main.ts 引入vue,引入app盒子,挂载app到根目录;
  5. yarn create vite> 开始 | Vite 官方中文文档 (vitejs.dev)
  6. 购优偿app youchang-app;1. vue2. ts
  7. cd youchang-app
  8. yarn // 安装依赖;

启动/挂载

  1. yarn dev // 运行项目1. 切换logo /// iconfont 电商; 128尺寸,png,项目src-images内2. png 传ico // 输出96 或 723. 删除原有public/ ***.svg4. 电商app为空(虽然不知道为什么不要,那就不要好嘞)5. 删除文件6. 创建images 与 pages文件 与 main.ts 文件挂载;在这里插入图片描述1. main.ts中的挂载app需要修改为新建的pages下的index.vue;核对根元素是否为app或root;7. 创建基础文件vite-env.d.ts/// declare module "*.vue" {'#root'}

在这里插入图片描述

  1. 可能出现的问题:2.3为解决步骤1. 在这里插入图片描述2. tsconfig.json修改为bundler==>node在这里插入图片描述1. src 下的vite-env.d.ts添加在这里插入图片描述2. 当 “–moduleResolution” 为 “node16” 或 “nodenext” 时,相对导入路径需要 EcmaScript 导入中的显式文件扩展名。请考虑将扩展名添加到导入路径中。ts(2834)

路由vue-router*使用

  1. yarn add vue-router
  2. 创建router/index.ts
  3. 路由模式 history(做App统一用hash)
  4. routes 的路径 1. 重定向2. 组件的import 引入以及注册
  5. 渲染已经注册完成的components组件到pages/index.vue (挂载的盒子) 1. < router-view >< /router-view >
  6. 容易遗漏的: 1. router/index.ts中使用hash与Router是需要引用的,否则无法正常渲染;2. main.ts中的createApp 中router 的引入与挂载;

路由实现页面的跳转

  1. import 引入
  2. router.push跳转
  3. 跳转不动记得检查interceptor拦截器中next()使用否;

pinia状态管理器*

1. pinia 状态管理器(继承状态管理器)类似与vuex
2. 用户注册interface
3. pinia插件的开发与注册
4. login/home 实现数仓持久化 以及数仓内值的取用
  1. 安装yarn add pinia
  2. 全局注入
  3. pinia和vuex的区别 ​ 1. vuex遵循的是全局只能有一个数仓(只能有一个store实例new Vuex.Store({})),而pinia不一样 2. vuex集中管理,pinia松散式管理
  4. 创建store/useUserStore.ts (用户仓库)1. 引入;import{defineStore} from ‘pinia’;2. 导出;export default useUserStore3. 作用;全局多次需要直接获取到用户的信息import{ defineStore }from'pinia'// 为什么使用defineStore?// 创建接口const useUserStore =defineStore('user',{state():UserStore{return{ token:'', userInfo:({}as UserInfo)}},// 修改数据 -- pinia插件修改数据用action,取代了mutations; actions:{setToken(_newToken:string){this.token = _newToken;console.log('setToken被调用了');// 设置函数方法更新token值},setUserInfo(_newUserInfo:UserInfo){this.userInfo = _newUserInfo;// 设置函数方法更新userInfo值},}, getters:{tokenInfo():string{returnthis.token },myUserInfo():UserInfo{returnthis.userInfo }}})exportdefault useUserStore // 导出;

用户注册接口

  1. vite-env.d.ts1. 创建interface 接口;(承接上文pinia中使用的UserStore,UserInfo两个接口)
  2. 使用pinia的store数仓(两个页面之间数仓的修改与接收)1. 引入useUserStore2. 实例化调用store3. login./index.vue等页面使用;4. home./index.vue接收login修改的token值

特点:可获取修改后的值,但是页面刷新后数值就消失

参考pinia中文文档,解决问题;

pinia 插件的开发;

  1. main.ts1. 实例化pinia /将原本直接挂载的createPinia() 切换为pinia注册上去2. 开发plugin3. plugin插件注册到pinia
  2. 取出plugin中的store,使用解构赋值获取,并调用$subscribe订阅数据的函数;1. 可获取到store数据仓发生改变后的newState值,2. 利用sessionStorage存储到缓存内;3. 加入判断条件cache(之前存入的本地缓存)存在时,将store.某值取出来并赋予> 每次页面刷新时会执行该plugin插件,数仓会再次取出数值,持久性完成。

login/home页持久化测试

  1. 将token值的获取拓展开userInfo
  2. login页面修改数仓内数值token,userInfo
  3. 此时调用main.ts中plugin ;- 缓存去到上次刷新前取出的值后,Json.parse转为对象后遍历对象,将其存储回数仓store;
  4. 页面跳转到home页面;- home页面设置数仓中userInfo内取出的常量name值,显示到页面- 40706050822452.png&pos_id=img-IUOrUU2u-1729446020194)
1. pinia结合路由实现用户登录认证
    1. 拦截器,识别用户登陆状态
    2. meta路由的固定传参,决定路由是否需要背拦截;
    3. meta/params/query 路由传参的三种方式

token校验正确性与时效性;

  1. token-info信息由token值与当前时间构成
  2. 间隔开一同加密后存储进入数仓中;
  3. 存入多个位置后比对,以验证正确性;store/sessionStorage
  4. interceptor.ts 完善token信息除开存在与否并验证是否正确;

URLENCODED 与form-data的区别;

后端生成JWT;

  1. 安装插件1. 加密生成tokennpm install jsonwebtoken2. 解析jwtnpm install express-jwt
  2. 引入jwt,设置加密对象加密算法有效时间/* 登录请求 通常放在登录或注册时*/const jwt = require("jsonwebtoken");router.get("/", function (req, res, next) { let token = jwt.sign({ username: "zhangsan" }, "test123456", { expiresIn: "360s", algorithm: "HS256", }); console.log(req.query); res.json({ code: 1, msg: "注册成功", token, });});
  3. 使用apipost 软件测试登录- 此时所有的路由都需要header传入token值,方可正常访问否则报错401- 无header内Authorization 传递值时- 正常做法:Authorization:Bearer xxxxxxxx// 务必bearer后面加上空格,除非后端设置过并且特别注明;

封装解密加密工具

  1. 使用CryptoJS库AES与enc。封装encodeApi、decodeApi加密解密工具类。
  2. 开发tools或utils助手工具(便于多次加密/解密)1. 安装:yarn add crypto-js2. 引入:crypto-js3. AES.encrypt(变量,‘加密设置字符串’).toString // 注释中内容4. AES.decrypt(变量,‘加密设置字符串’)
  3. 创建utils/index.ts
  4. 将main.ts中使用AES的位置切换为自己开发的工具encodeApi/decodeApi
  5. 可能会报的错误 4. 引入报错1,直接去全局定义 5. 引入报错2,tsconfig.node.json修改// 但一般不影响运行;
  6. 解决思路:- key设置为16/32/48位数- 关闭项目重新启动尝试- 字符串清空换行符;import {AES,enc} from 'crypto-js'const key = '' // 16/32/48 ;bit,不能有空格换行等;export function encodeApi(value:string){ return AES.encrypt(value,key).toString()}export function decodeApi(msg:string){ return AES.decrypt(msg,key).toString(enc,UTF8) //}

封装拦截路由

  1. 封装拦截路由。验证除欢迎登录注册等页面的接收到token正确性、时效性。//1. 创建store;const userStore =({'user',state():userStore{// 这里函数return{ token:''; userInfo:({}as userInfo)}}, getters:{tokenInfo(v){returnthis.token;},userInfo(v){returnthis.userInfo;}}, actions:{setToken(v){this.token = v },setInfo(v){this.userInfo = v;}}})exportdefault userStore;//2. 创建router;meta:{needAuth:true}import{createRouter,Router,createWebHashHistory}from'vue-router'const router:Router =createRouter({ history:createWebHashHistory(), routes:[{path:'/',redirect:'/login'},{path:'/login',redirect:'/login'},{path:'/home',redirect:'/home',meta:{needAuth:true,}}]})//3. 路由守卫router.beforeEach(interceptor)router.beforeEach(intercepter)exportdefault router;//4. 路由拦截器的封装;import userStore from'../store/userStore'import{decodeApi,encodeApi}from'../utils/index.ts'functioninterceptor(to,from,next):{if(to.meta.needAuth){let token =userStore().token;let _token = sessionStorage.getItem('tokenInfo')if(!_token){next('/login')// 去登录}else{ _token =decodeApi(_token).split('--')[0],let time =decodeApi(_token).split('--')[1]if(Date.now()- time>=2*60*60*1000){next('/login')// 超时去登录}else{if(token === _token){next()}else{next('/login')}}}}else{next()}}// 由于设置了重定向路由,next('/') === next('/login')

免登录思路

  1. 登录页与主页免登录,Pinia开发数据持久化插件。// pinia版本数据持久化;// 0. 安装引入piniayarn add pinia;import{createPinia}from'pinia';import App from'./pages/index.vue';//引入容器import{createApp}from'vue'//引入vuelet pinia =createPinia();cretateApp(App).use(pinia).mount('#root')// 0.1 创建数仓;const userStore =defineStore({'user',state(){return{ userInfo, userToken }}, getters:{getInfo(){},getToken(){}}, actions:{}})// 1. 登录页填写信息;<button @click='saveEvt'>functionsaveEvt(){// 存入数仓; store.setInfo();}// 2. 主页从数仓获取内容;{{uname}}{{uage}}import userStore from'../store/userStore';const store =userStore()let uname:string = store.userInfo.uname;// 3. 开发pinia的plugin插件实现数据持久化;functionplugin({store}:any){// 3.2解构数仓log(arguments)// 3.1了解到数仓内有目标内容store,$subscribe发布方法;let cathe = sessionStorage.getItem('userInfo')//3.4 查询本地有无实现持久化的数据if(cathe){let info : any =JSON.parse(decodeApi(cache));for(let key in info){ store[key]= info[key]// 将本地缓存的数据依次存入store数仓 end至此完成持久化数据封装}} store.$subscribe(function(_,newState)){// 3.3 调用发布方法,将数仓内的数据缓存到sessionb本地,防止刷新丢失数据,实现数据持久化;let str =encodeApi(JSON.stringify(newState)); sessionStorage.setItem('userInfo',str)}}pinia.use(plugin)// 插件注册到pinia库,便于使用;// vuex 版本数据持久化;createApp(App).use(pinia)

vant4 快速搭建页面,文件上传组件使用

  1. Vant4组件搭建注册页。包括头像图片文件地址等用户信息上传。1. van-uploader 组件<van-field name="uploader" label="用户头像"><!-- 这里的#input表示v-slot的简写;等价于slot="input"--><!-- formData对象将json数据转化为表单对象 --><template #input><van-uploader v-model="userInfo.photo":after-read="filePicker" multiple :max-count="1"/></template></van-field>2. fd 实例 functionfilePicker(obj:any){// console.log(arguments); //就可直接拿到文件对象;let fd =newFormData();// console.log(fd);// 当前元素节点后面插入元素element; fd.append('file',obj.file)// 调用useApi.ts中定义的接口uploadFileApi(fd).then((d:any)=>{// console.log(d)if(d.code ==1){// console.log(d.data);// if(d.code == 200){ userInfo.photo =[{url:'/apis/'+d.data[0].path}]// console.log(userInfo.photo[0].url);// userInfo.photo =[{url:'apis'+d.data[2].pimg}]// console.log(d.data[2].pimg);}})}// 3. 后端;let express =require('express')let router = express.Router();const multer =require('multer');const fs =require('fs');let{Upload}=require('../models/index.js')// 文件上传的存储目录// var imgupload = multer({dest:'www/imgupload'});// 单个 可行postapi 网页可行// 多个: postapi可 网页不可router.post('/complate',multer({ dest:'www/imgupload/'}).array('file',9),function(req,res,next){ console.log(req.files);const files = req.files;const fileList =[]; files.forEach(v=>{let file = v; fs.renameSync(file.path,`www/imgupload/${file.originalname}`) file.path =`www/imgupload/${file.originalname}` fileList.push(file) Upload.create(file)});// res.send(fileList) res.json({ code:1, data:fileList, msg:'上传成功'})})// 设置静态文件//必须设置在use文件前方!!!app.use('/www',express.static('www'));//将文件设置成静态,才能公开访问该文件夹下面的图片,真的很关键;app.set('views', path.join(__dirname,'views'));app.set('view engine','ejs');

主页列表滚动实现节流思路

functiongetList(){homeRecomendApi({pagesize:4,pagenum:pagenum.value})//一次请求数量,请求的页面.then(d=>{//遍历data的list
        list.value()})
        loading.value =false// 调用api获取一组列表完成}functionscrollEvt(e:PointerEvent){// 指针事件,鼠标事件类似将鼠标,触摸,触控笔三种事件的整合let div: HTMLDivElement = e.target as HTMLDivElement;
        console.log(div.clientHeight,div.scrollTop,div.scrollHeight,div);let hasToBotton: boolean = div.scrollHeight -80<(div.clientHeight + div.scrollTop)
        console.log(hasToBotton);//false // 整个除开头与导航的高度-尾部提示文字 < 内容可视高度 + 顶部滚过的高度;if(hasMore.value &&!loading.value && hasToBotton){//当前page内容数据库加载完成,调用api接口完成修改true,此页滚到底部为true,// 此处开启节流;
            loading.value =true;// 加载完成;
            pagenum.value +=1;
            console.log(pagenum.value+'当前页数节流');// 加载数据getList();}}
  1. 搭建购物车、地址页,增删商品、地址、编辑信息;// 地址弹出层放在大盒子外侧;// 遇事不决arguments和events事件对象;总体不难,按规则写
  2. 百度地图接口的使用。https://lbsyun.baidu.com/cms/jsapi/reference/jsapi_reference.html
  3. Node.JS与Mongodb搭建后端,使用jsonwebtoken、express-jwt分别加密、解析token。
   // 1. 加密token--login页面;
   let jwt = require('jsonwebtoken')
   const key =''
   let token = jwt.sign({phone:req.body.phone},
   key,
   {expiresIn:'3600s', //1h有效期
   algorithm:'HS256'})
   // 2. 解密token
   // 排除哪些不需要token
var {expressjwt} = require('express-jwt');
// var { key } = require("./routes/index.js");
// 下面的方法拦截必须写在静态资源值后,否则无法访问,页面不可正常加载;
app.use(
  expressjwt({
    secret:key,  // 解密的密码
    algorithms:["HS256"], // 解密的算法
}).unless({             // 排除:定义:默认所有的接口都需要传入token,在这里排除不需要的token接口
  path:[
  // 可使用正则表达式
  ]
})
)

   

      
标签: web app vue typescript

本文转载自: https://blog.csdn.net/m0_69364468/article/details/143102023
版权归原作者 不是周末 所有, 如有侵权,请联系我们删除。

“购优偿WebApp开发整理”的评论:

还没有评论