uni-app
概念
uni-app 是一个使用 Vue.js 开发所有前端应用的框架,开发者编写一套代码,可发布到iOS、Android、Web(响应式)、以及各种小程序(微信/支付宝/百度/头条/飞书/QQ/快手/钉钉/淘宝)、快应用等多个平台。
特点:
1 基于vue的前端框架 (学习成本很低)
2 一套代码,多端运行(爆炸) (编译成各大平台语言) ,我们需要花精力去适配
3 是一个缝合怪(指令、技术等采用vue框架) 、组件 、api 、路由、生命周期、采用的小程序
使用工具: hbuilderx
https://www.dcloud.io/hbuilderx.html
其他:
1 打印:clog
2 开启终端: alt+c
3 工具--插件安装--
新建uni-app项目
文件--新建---项目--uni-app
项目结构
pages (页面)
目录
目录.vue
static (装静态资源--图片等)
app.vue(全局业务、全局样式)
index.html
main.js 入口js
manifest.json 配置文件(配置appId等)
pages.json(全局配置,类似于小程序的app.json),比如导航拦、tabbar、路由
编译打包到各大平台
1 微信小程序
1 开启微信开发者工具的服务端口
设置--安全设置---服务端口打开
2 在hbuilder中编译
运行--运行到小程序模拟器---微信开发者工具
第一次会弹框:让你指定微信开发者工具的exe文件所在目录
一定要记得在manifest.json (微信小程序配置:appId)
成功后会在项目中生成unpackage目录:
2 h5
内置h5(插件支持)
方式1 点击右上角的预览
方式2 运行--运行到内置浏览器
外置h5 (使用浏览器来解析)
运行--运行到浏览器---chrome
3 android (模拟器)
1 打开mumu模拟器--系统应用---设置----开发者选项---开启总开关---开启USB调试
2 hbuilderx;运行--运行到手机或模拟器---ADB路径设置---Android模拟器端口:7555
我的是:C:/HBuilderX.3.6.5.20221121/HBuilderX/plugins/launcher/tools/adbs/adb.exe
3 hbuilderx;运行-运行到android app基座
新建页面
鼠标悬停到pages目录,右键-新建页面
打钩创建同名目录
打钩配置json
pages.json
1 页面配置
path(路由) + style(页面标题配置等)
"pages": [
{
"path": "pages/index/index",
"style": {
//单独配置当前页面相关选项,比如标题、颜色等
"navigationBarTitleText": "uni-app"
}
}
2 全局导航拦配置:
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
},
3 tabbar
"tabBar": {
"color": "#7A7E83",
"selectedColor": "#3cc51f",
"borderStyle": "black",
"backgroundColor": "#ffffff",
"list": [
{
"pagePath": "pages/home/home",
"iconPath": "static/img/home.png",
"selectedIconPath": "static/img/home2.png",
"text": "首页"
},
{
"pagePath": "pages/cat/cat",
"iconPath": "static/img/cat.png",
"selectedIconPath": "static/img/cat2.png",
"text": "分类"
},
{
"pagePath": "pages/my/my",
"iconPath": "static/img/my.png",
"selectedIconPath": "static/img/my2.png",
"text": "我的"
}
]
生命周期
应用级
onLaunch: function() {
console.log('App Launch')
},
onShow: function() {
console.log('App Show')
},
onHide: function() {
console.log('App Hide')
}
页面级
onLoad(options)()
onShow(){}
onPullDownRefresh(){}下拉刷新
onReachBottom(){}触底分页
组件级
beforeCreate 在实例初始化之前被调用。详见
created 在实例创建完成后被立即调用。详见
beforeMount 在挂载开始之前被调用。详见
mounted 挂载到实例上去之后调用。详见 注意:此处并不能确定子组件被全部挂载,如果需要子组件完全挂载之后在执行操作可以使用$nextTickVue官方文档
beforeUpdate 数据更新时调用,发生在虚拟 DOM 打补丁之前。详见 仅H5平台支持
updated 由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。详见 仅H5平台支持
beforeDestroy 实例销毁之前调用。在这一步,实例仍然完全可用。详见
destroyed Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。详见
规范
1 指令用到vue
生命周期函数、api、组件、路由等用到小程序
2 关于api其实就由曾经的wx.xxx改为了uni.xx
3 布局:为了更好的兼容,请都用弹性布局
4 路径问题:
<image src="/static/...."
<image src="@/static/...."
<image src="../static/..."
import xx from '@/....'
import xx from '../....'
路由跳转
1 标签
<navigator url="" open-type="navigate/switchTab"
2 js
uni.navigateTo({}) 跳转非tabbar
uni.switchTab({}) 跳转tabbar
传参:
1 通过 ?传递
2 通过onload(options){}钩子函数来接受
组件通信(和vue一样)
1 组件引入
前置:在项目的根目录下新建components目录用来存储组件
1 右键components目录---》创建组件 (勾选创建同名组件)
2 在页面中import 引入+ components注册 即可把子组件当成标签使用(同vue)
2 通信问题
必然遵守单向数据流
父:
<son :name="name" @change="change"/>
methods: {
change(name){
this.name=name
}
}
子:
export default {
props:['name']//用来结束
//更新就用emit(自定义事件)
this.$emit('change',this.t)
测试其他 (和vue一样)
1 数据绑定(双向)
<input type="text" v-model="user.username">
data() {
return {
user:{
username:""
}
}
},
2 列表渲染
<view v-for="item in stus" :key="item.id">
{{item.name}}--{{item.gender==1?"男":"女"}}
</view>
3 条件渲染
<view v-for="item in stus" :key="item.id">
<text v-if="item.gender==1">{{item.name}}--{{item.gender==1?"男":"女"}}</text>
</view>
4 监听
watch:{
user:{
handler(newVal){
console.log("更新后的对象时",newVal);
},
deep:true,
immediate:true
},
},
5 计算属性
computed:{
sum(){
return this.n1+this.n2
}
},
布局的单位:依然采用rpx
共享仓库的做法:
1 效仿小程序使用globalData
使用条件:如果需要在全局中存储一些从常量(不会被更改的数据),比如
url地址、密钥、端口等
使用:位置:App.vue
export default {
globalData:{
url:"http://localhost:3000"
}
页面:
<script>
let app=getApp();
export default {
data() {
return {
url:app.globalData.url
}
},
2 推荐使用vuex(实时共享数据)
比如登录后的userInfo
uni-app已经内置了vuex,因此不用额外下载插件
vuex使用场景:多个页面共享数据
步骤
1 项目下新建store目录,store下新建index.js和modules目录
2 分模块,在modules新建模块.js
export default {
namespaced:true,
state:{
user:null
},
mutations:{
change_user(state,data){
state.user=data
}
},
}
3 编辑index.js
//引入Vue
import Vue from 'vue'
//引入vuex
import Vuex from 'vuex'
//使用Vuex
Vue.use(Vuex)
// import clas from './modules/clas.js'
import users from './modules/users.js'
//暴露仓库对象(store)
export default new Vuex.Store({
//分模块
modules: {
// clas,
users
}
})
4 编辑main.js
import store from '@/store/index.js'
const app = new Vue({
store,
})
使用:
1 在页面上通过辅助函数来实现
<template>
<view>
<!-- <navigator url="/pages/test/test?id=1&name=abc">跳转test</navigator>
<button @click="go">跳转cat</button> -->
<!-- <button @click="setUser">为仓库的user赋值</button> -->
{{user.username}}
</view>
</template>
<script>
import {createNamespacedHelpers} from 'vuex'
let {mapState,mapMutations}=createNamespacedHelpers("users");
export default {
computed:{
...mapState(['user'])
},
data() {
return {
}
},
methods: {
...mapMutations(['change_user'])
},
onLoad() {
//模拟ajax
setTimeout(()=>{
//假数据
let user={username:"aaa",password:"111"};
this.change_user(user)
},2000)
}
}
</script>
<style>
</style>
2 js上原生的方式
想办法得到store对象
import store from '@/store/index.js'
1 获得:store.state.模块.属性
2 调用mutations:store.commit("模块/方法",参数)
3 调用actions:store.dispatch("模块/方法",参数)
异步请求
语法:
uni.request({
url:"",
data:{
},
header:{
},
method:"get/post",
success(res){},
fail(res){},
complete(){
}
})
封装:
http/request.js
export default function({url,method='GET',data}){
return new Promise((resolve,reject)=>{
//开启加载动画
uni.showLoading({
title: '加载中'
});
uni.request({
url,
data,
header:{
},
method,
success(res){
resolve(res)
},
fail(res){
reject(res)
},
//无论如何都会执行
complete(){
uni.hideLoading()
}
})
})
}
main.js
import request from '@/http/request.js'
//挂载全局
Vue.prototype.$request=request
触底分页
<template>
<view>
<view
v-for="item in goods" :key="item.goods_id"
style="height: 600rpx; border: 1rpx red solid;">
<image :src="item.goods_big_logo" mode=""></image>
</view>
</view>
</template>
<script>
export default {
data() {
return {
goods:[],
pagenum:1,
total:0
}
},
methods: {
async getPage(){
let res=await this.$request({
url:"https://api-hmugo-web.itheima.net/api/public/v1/goods/search",
data:{
pagenum:this.pagenum,
pagesize:3
}
})
console.log(res.data.message);
this.goods.push(...res.data.message.goods)
// this.total=res.data.message.total
this.total=14
}
},
onReachBottom(){
if(this.goods.length<this.total){
this.pagenum++;
this.getPage()
}else{
uni.showToast({
title: '商品已经到头了!!',
duration: 2000
});
}
},
onLoad() {
this.getPage()
}
}
</script>
<style>
</style>
下拉刷新
步骤:
1 开启当前页面支持下拉刷新的开关pages.json
{
"path": "pages/my/my",
"style": {
"enablePullDownRefresh": true
}
}
2 开启总开关后我们有两种方法触发刷新:
1 人为的往下滑动手机
2 通过api来实现:(该方法需要主动关闭)
uni.startPullDownRefresh()
uni.stopPullDownRefresh()
3 钩子函数:
onPullDownRefresh(){
},
条件编译
作用:跨端兼容
执行原理:
条件编译是用特殊的注释作为标记,在编译时根据这些特殊的注释,将注释里面的代码编译到不同平台。
语法:
#ifdef 或者 #ifndef 平台
代码区域
#endif
#ifedf: 代码只能在该平台生效
#ifndef :代码在除开该平台之外的地方生效,该平台反而不能生效
注释分为三种:
js://
css:/**/
布局: <!-- -->
demo-js:
//#ifdef MP-WEIXIN
console.log("在小程序才能生效");
//#endif
demo-css
<style scoped>
.t{
font-size: 50rpx;
/* #ifdef MP-WEIXIN*/
color:red
/* #endif */
}
</style>
demo-template
<!-- #ifdef MP-WEIXIN -->
<text class="t">沙皮狗</text>
<!-- #endif -->