怎么用Taro+Vue3开发小程序
导读:本文共9529字符,通常情况下阅读需要32分钟。同时您也可以点击右侧朗读,来听本文内容。按键盘←(左) →(右) 方向键可以翻页。
摘要: 微信小程序是以微信为运行环境的一种应用,其实质是 Hybrid 技术的应用,Hybrid App 即混合模式移动应用,因此与 H5 类似,但又比 H5 拥有很多原生的能力,例如调用位置信息和摄像头等。小程序的开发方式与 H5 十分相似,用的也是 JavaScript、HTML、CSS 语言。因此,小程序开发可以说是一名前端工程师必须要掌握的技能。原生小程序开发有... ...
目录
(为您整理了一些要点),点击可以直达。微信小程序是以微信为运行环境的一种应用,其实质是 Hybrid
技术的应用,Hybrid App 即混合模式移动应用,因此与 H5
类似,但又比 H5 拥有很多原生的能力,例如调用位置信息和摄像头等。
小程序的开发方式与 H5 十分相似,用的也是 JavaScript
、HTML
、CSS
语言。
因此,小程序开发可以说是一名前端工程师必须要掌握的技能。
原生小程序开发有一定的学习成本,现如今市面上有很多开发小程序的第三方多端框架,如果不是追求极致性能和稳定,还是不要用原生小程序开发了,开发效率太低。
第三方多端框架中,taro
和 uni-app
的使用度是最广的,一般来说,做技术选型时,团队用 react
,就用 taro,团队用 vue
,就用 uni-app,两者之间没有什么优劣之分,都挺好用的。
但很多开发者可能不知道,taro3.0 以上版本是支持使用 vue 的,本篇文章就来介绍一下如何使用 Taro3 + Vue3 开发微信小程序。
我根据网上的资料完成了本项目的搭建之后,用本项目开发过一个小程序,那种开发体验真的是超越了我以往开发过的所有项目,非常丝滑(可能是我第一次写 vue3 的 script setup 吧,用起来确实很舒服)。
目标功能
集成 vue3,使用
script setup
语法开发集成
Typescript
代码检查和格式优化
全局状态管理
小程序分包配置
样式封装,兼容刘海儿屏等样式问题
http 方法封装
主要技术栈
Taro3
Vue3
TypeScript
NutUi
Pinia
vue3 刚发布时,由于没有合适的 ui 框架支持,我学习 vue3 的热情直接被劝退了。直到现在,类似于 quasar、element-plus、ant-design-vue 等优秀框架陆续支持 vue3,并且许多 vue3 项目被用到了生产环境中,才发现大家是把 vue3 真的用起来了。
比如我们公司隔壁项目组,重构项目就用了 vue3,这时我才发现自己学习 vue3 有点晚了(tips:前端真的太卷了)
NutUI 是京东风格的移动端组件库,它支持使用 Vue 语言来编写可以在 H5,小程序平台上的应用,帮助研发人员提升开发效率,改善开发体验。
我是从 Taro 文档 知道 NutUI 的,taro 官方推荐使用 NutUI 开发,他们似乎也都是来自京东同一个开发团队,我抱着试一试的心态上手使用,使用体验还不错。
Pinia 是一个用于 Vue 的状态管理库,类似 Vuex, 是 Vue 的另一种状态管理方案,支持 Vue2 和 Vue3。
我第一次接触前端状态管理工具,是刚实习时公司的一个后台管理系统,用的 dva,那可叫一个折磨啊,差点直接把我劝退。后面慢慢熟悉了一些,但是不管用 redux,还是 vuex,还是觉得写着麻烦。
这次尝试使用 Pinia,用起来确实很舒服,符合直觉,易于学习 ,有点类似于 recoil,但没有 recoil 那么多的概念和 API,主体非常精简,极易上手。Pinia 快速入门
vscode 需安装插件
Eslint
Prettier
Volar
与vetur
相同,volar
是一个针对 vue 的 vscode 插件,不过与 vetur 不同的是,volar 提供了更为强大的功能。
Volar 介绍
搭建项目架构
初始化项目
初始化项目之前,需安装 taro,请参考 Taro 文档,完成 taro 安装
使用命令创建模板项目:
taroinitmyApp
安装 cli 用来执行构建等操作,之后启动项目,会生成一个 dist 目录
yarnadd@tarojs/cliyarndev:weapp
打开微信开发工具 工程目录需要指向构建出来的 dist 文件
Hello world 出现,项目成功跑起来了!
设置代码规范
代码规范 ESlint
代码格式化 Prettier
提交前检查 husky
个人认为,eslint + prettier 足以应付大部分前端代码规范问题了,且配置起来很简单,有特殊需求也可继续配置。
安装依赖
yarnadd@vue/eslint-config-prettier@vue/eslint-config-typescripteslint-plugin-prettiervue-tschusky-D
设置代码规范和格式化规则
.eslintrc.js
module.exports={root:true,env:{node:true,'vue/setup-compiler-macros':true},extends:['plugin:vue/vue3-essential','eslint:recommended','@vue/prettier','@vue/typescript'],parserOptions:{parser:'@typescript-eslint/parser'},rules:{'prettier/prettier':['error',{singleQuote:true,semi:false,trailingComma:'none',arrowParens:'avoid',printWidth:100}],'no-console':process.env.NODE_ENV==='production'?'warn':'off','no-debugger':process.env.NODE_ENV==='production'?'warn':'off'}}
.prettierrc
{"tabWidth":2,"singleQuote":true,"semi":false,"trailingComma":"none","arrowParens":"avoid","endOfLine":"auto","printWidth":100}
在 package.json 中 script 添加 Ts 检查命令和 Eslint 检查命令
"scripts":{"tsc":"vue-tsc--noEmit--skipLibCheck","lint":"eslint--ext.vue--ext.js--ext.tssrc/"}
添加 husky 触发 Git 钩子,代码提交前检查
npxhuskyinstall
编辑 pre-commit 执行 Eslint 检查和 Ts 检查
#!/bin/sh."$(dirname"$0")/_/husky.sh"echo"---eslintstart---"npmrunlintecho"---eslintend---"echo"---tslintstart---"npmruntscecho"---tslintend---"
至此,项目的代码规范和格式规范配置完毕,多人协作也不是问题了。
引入 NutUI
yarnadd@nutui/nutui-taro
在 .babelrc
或 babel.config.js
中添加配置:
module.exports={//...plugins:[['import',{libraryName:'@nutui/nutui',libraryDirectory:'dist/packages/_es',camel2DashComponentName:false},'nutui3-vue'],['import',{libraryName:'@nutui/nutui-taro',libraryDirectory:'dist/packages/_es',camel2DashComponentName:false},'nutui3-taro']]}
按需引入,安装插件 babel-plugin-import
yarnaddbabel-plugin-import-D
样式处理 因为 nutui 的设计稿是 375 的 所以将框架的设计尺寸调整为 375
项目配置文件 config/index.js 中配置:
designWidth:375
app.ts
import{createApp}from'vue'import{Button}from'@nutui/nutui-taro'constapp=createApp()app.use(Button)
index.vue 中,nut-button 组件直接在 template 中写,不用再引入
<template><viewclass="index"><text>{{msg}}</text><nut-buttontype="primary">主要按钮</nut-button></view></template>
说实话,配置起来还是有点麻烦,不过按照官网文档说明来配也没有踩坑,还行。
小程序分包配置
小程序主包超过 2M,就无法真机预览了,为了提前做好准备在一开始就进行分包处理。比如下面这个小程序的配置,分了四个包。
app.config.ts
pages:['pages/create/index','pages/find/index','pages/my/index'],subpackages:[{root:'pages/featureA',pages:['index/index']},{root:'pagesSub/search',pages:['index']},{root:'pagesSub/my',pages:['detail/index','about/index']},{root:'pagesSub/book',pages:['detail/index','person/list/index','person/detail/index']}],
可以在小程序开发工具编辑器里的代码依赖分析,查看主包和分包的大小
使用 script setup 语法封装小程序页面生命周期方法
hooks/life.ts
import{getCurrentInstance}from'@tarojs/taro'import{onMounted}from'vue'constCurrent=getCurrentInstance()exportfunctionuseDidShow(callback){onMounted(callback)Current?.page?.onShow&&(Current.page.onShow=callback)}exportfunctionusePullDownRefresh(callback){Current?.page?.onPullDownRefresh&&(Current.page.onPullDownRefresh=callback)}
使用
import{useDidShow}from'@/hooks/life'useDidShow(()=>{//console.log('onShow')})
安装 Pinia 进行状态管理
yarnaddpiniayarnaddtaro-plugin-pinia
项目配置文件 config/index.js 中配置:
plugins:['taro-plugin-pinia']
以管理用户信息和用户登录状态为例,实现一个用户登录功能
需要处理的文件代码如下:
stores/auth.ts
import{defineStore}from'pinia'interfaceUserInfoProp{nickName:stringavatarUrl:string}constuseAuth=defineStore({id:'authInfo',state:()=>({userInfo:{nickName:'',avatarUrl:''},isLogin:false}),actions:{login(){this.isLogin=true},logout(){this.isLogin=false},setUserInfo(userInfo:UserInfoProp){this.userInfo=userInfo}}})export{useAuth}
stores/index.ts
import{createPinia}from'pinia'import{useAuth}from'./auth'exportconststore=createPinia()conststoreObj={auth:useAuth}//封装成useStore的形式,这样一看引用就知道是store的数据exportfunctionuseStore(key:string){returnstoreObj[key]()}
个人中心 index.vue
<template><mainv-if="isLogin"><user-info/></main><mainv-else><nut-buttontype="primary"@click="handleLogin">微信一键登录</nut-button></main></template><scriptsetup>importTarofrom'@tarojs/taro'import{computed}from'vue'import{useStore}from'@/stores'importUserInfofrom'./userInfo.vue'constauth=useStore('auth')constisLogin=computed(()=>auth.isLogin)consthandleLogin=()=>{setTimeout(()=>{//模拟后端请求得到token和userInfoTaro.setStorageSync('token','xxxx')auth.setUserInfo({nickName:'林',avatarUrl:'https://img12.360buyimg.com/imagetools/jfs/t1/143702/31/16654/116794/5fc6f541Edebf8a57/4138097748889987.png'})auth.login()},500)}</script></script>
userInfo 组件
<template><article><nut-avatarsize="large":icon="userInfo.avatarUrl"></nut-avatar><spanclass="ellipsisname">{{userInfo.nickName}}</span></article></template><scriptsetup>importTarofrom'@tarojs/taro'import{computed}from'vue'import{useStore}from'@/stores'constauth=useStore('auth')constuserInfo=computed(()=>auth.userInfo)</script>
总的来说, pinia 写起来是非常简洁的,这种类 react hooks 的写法,我是非常喜欢的
请求方法封装
http.ts
//封装axios的请求,返回重新封装的数据格式//对错误的统一处理import{HttpResponse}from'@/common/interface'importTarofrom'@tarojs/taro'importpublicConfigfrom'@/config/index'importaxios,{AxiosInstance,AxiosRequestConfig,AxiosResponse,Canceler}from'axios-miniprogram'importerrorHandlefrom'../common/errorHandle'constCancelToken=axios.CancelTokenclassHttpRequest{privatebaseUrl:stringprivatepending:Record<string,Canceler>constructor(baseUrl:string){this.baseUrl=baseUrlthis.pending={}}//获取axios配置getInsideConfig(){constconfig={baseURL:this.baseUrl,headers:{'Content-Type':'application/json;charset=utf-8'},timeout:10000}returnconfig}removePending(key:string,isRequest=false){if(this.pending[key]&&isRequest){this.pending[key]('取消重复请求')}deletethis.pending[key]}//设定拦截器interceptors(instance:AxiosInstance){instance.interceptors.request.use(config=>{console.log('config:>>',config)letisPublic=falsepublicConfig.publicPath.map(path=>{isPublic=isPublic||path.test(config.url||'')})consttoken=Taro.getStorageSync('token')if(!isPublic&&token){config.headers.Authorization='Bearer'+token}constkey=config.url+'&'+config.methodthis.removePending(key,true)config.cancelToken=newCancelToken(c=>{this.pending[key]=c})returnconfig},err=>{errorHandle(err)returnPromise.reject(err)})//响应请求的拦截器instance.interceptors.response.use(res=>{constkey=res.config.url+'&'+res.config.methodthis.removePending(key)if(res.status===200){returnPromise.resolve(res.data)}else{returnPromise.reject(res)}},err=>{errorHandle(err)returnPromise.reject(err)})}//创建实例request(options:AxiosRequestConfig){constinstance=axios.create()constnewOptions=Object.assign(this.getInsideConfig(),options)this.interceptors(instance)returninstance(newOptions)}get(url:string,config?:AxiosRequestConfig):Promise<AxiosResponse>|Promise<HttpResponse>{constoptions=Object.assign({method:'get',url:url},config)returnthis.request(options)}post(url:string,data?:unknown):Promise<AxiosResponse>|Promise<HttpResponse>{returnthis.request({method:'post',url:url,data:data})}}exportdefaultHttpRequest
request.ts
importHttpRequestfrom'./http'importconfigfrom'@/config/index'constbaseUrl=process.env.NODE_ENV==='development'?config.baseUrl.dev:config.baseUrl.proconstrequest=newHttpRequest(baseUrl)exportdefaultrequest
以获取图书列表和图书详情为例
apis/book.ts
importrequestfrom'../request'exportfunctiongetBookList(){returnrequest.get('books/getBookList')}exportfunctiongetBookDetail(id:number){returnrequest.post('books/getBookDetail',{id})}
请求方法封装还是用到了 axios
,只是用的是 axios-miniprogram
,写法和 web 端基本一致,http.js 文件引用的一些模块太多,本文没有列出来,可以直接访问本项目 github 地址查看。
样式封装
iPhoneX 底部横线适配
assets/styles/common.scss
.safe-area-bottom{padding-bottom:constant(safe-area-inset-bottom);padding-bottom:env(safe-area-inset-bottom);}
刘海儿屏适配
assets/styles/hairline.scss
@mixinhairline-common(){position:absolute;box-sizing:border-box;content:'';pointer-events:none;}@mixinhairline(){@includehairline-common();top:-50%;right:-50%;bottom:-50%;left:-50%;border:0solid#eaeaea;transform:scale(0.5);}@mixinhairline-top($color,$left:0,$right:0){@includehairline-common();top:0;right:$right;left:$left;border-top:1pxsolid$color;transform:scaleY(0.5);}@mixinhairline-bottom($color,$left:0,$right:0){@includehairline-common();right:$right;bottom:0;left:$left;border-bottom:1pxsolid$color;transform:scaleY(0.5);}[class*='van-hairline']{&::after{@includehairline();}}.van-hairline{&,&--top,&--left,&--right,&--bottom,&--surround,&--top-bottom{position:relative;}&--top::after{border-top-width:1px;}&--left::after{border-left-width:1px;}&--right::after{border-right-width:1px;}&--bottom::after{border-bottom-width:1px;}&,&-unset{&--top-bottom::after{border-width:1px0;}}&--surround::after{border-width:1px;}}
多行文字省略
assets/styles/ellipsis.scss
@mixinmulti-ellipsis($lines){display:-webkit-box;overflow:hidden;text-overflow:ellipsis;-webkit-line-clamp:$lines;-webkit-box-orient:vertical;}@mixinellipsis(){overflow:hidden;white-space:nowrap;text-overflow:ellipsis;}.ellipsis{@includeellipsis();}.multi-ellipsis--l2{@includemulti-ellipsis(2);}.multi-ellipsis--l3{@includemulti-ellipsis(3);}
</div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
怎么用Taro+Vue3开发小程序的详细内容,希望对您有所帮助,信息来源于网络。