快速上手
什么是uni-app
uni-app 是一个使用 Vue.js 开发所有前端应用的框架,开发者编写一套代码,可打包成 H5、小程序、APP 发布到多端
HBuilderX 是开发 uni-app 应用的神兵利器:
下面是一些推荐的插件,更多插件请访问 插件市场:
uni-app(vue2/vue3)编译器:将 Vue 代码打包到多端dart-sass:解析 scss 语法prettier:代码格式化uni-ui:跨端 UI 组件库pinia-plugin-unistorage:本地持久化,需要与 Pinia 配合使用uni-ajax:参考 axios 封装的网络请求
创建uni-app项目
方式一 vue-cli方式
- 下载 Vue3版本 uni-app 模版
- 安装依赖
npm i - 打包运行
npm run xxx
方式二 HBuilderX(推荐)
- 新建项目
- 选择模版
- 打包运行
运行uni-app项目
运行到浏览器
- 安装内置浏览器插件(可选)
- 打包运行
运行到小程序端
- 在
manifest.json文件中添加微信小程序 AppID - 在小程序中开启服务端口
设置>安全>服务端口 - 打包运行
运行到安卓真机
- 安装
App真机运行插件 - 在手机上开启USB调试
关于手机>版本号>连续点击开启开发者模式>允许USB调试 - 使用 USB 线连接电脑和手机,并选择传输文件模式
- 打包运行
对于不同的手机系统,开发者模式的开启存在差异,具体步骤请百度
uni-app目录结构
eg.pages.json页面配置示例
{
// 路由&页面配置
"pages": [
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "首页"
}
},
{
"path": "pages/list/list",
"style": {
"navigationBarTitleText": "列表页"
}
}
],
// 页面全局配置
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
},
// 底部TabBar配置
"tabBar": {
"color": "#999",
"selectedColor": "#333",
"borderStyle": "white",
"position": "bottom",
"list": [{
"text": "首页",
"pagePath": "pages/index/index",
"iconPath": "/static/home_default.png",
"selectedIconPath": "/static/home_active.png"
}, {
"text": "列表页",
"pagePath": "pages/list/list",
"iconPath": "/static/list_default.png",
"selectedIconPath": "/static/list_active.png"
}]
},
"uniIdRouter": {}
}
更多配置项请参考:uni-app 全局配置
App.vue 是根组件,相当于小程序中 app.js、app.wxss 两个文件的组合,常用来定义全局样式
uni-app生命周期
uni-app 项目中 页面的生命周期 参考小程序的生命周期,组件的生命周期 参考 Vue 的生命周期。不同生命周期的可用情况如下:
eg.生命周期示例
<script setup>
// Vue组件生命周期
import { onMounted } from 'vue'
// 小程序生命周期 只能在页面上使用
import { onLaunch, onLoad } from '@dcloudio/uni-app'
onLoad((params)=>{
console.log('页面参数:', params)
getList()
})
</script>
uni-app混合开发
Q:uni-app 项目的开发模式是?
A:基于 Vue2/Vue3语法 结合 微信小程序 组件、内置API 、生命周期进行混合开发
eg.uni-app混合开发示例
<template>
<view style="padding: 10px">
<view>我是块元素</view>
<text>我是行内元素</text>
<text>我是行内元素</text>
<text>我是行内元素</text>
</view>
<view style="border: 1px solid red; padding: 10px; margin: 10px">
<view v-for="item in list" :key="item">{{ item }}</view>
</view>
<button type="primary" @click="addItem">添加</button>
</template>
<script setup>
// 结合 Vue3 的 setup 语法使用【应用生命周期】和【页面生命周期】需要用到 @dcloudio/uni-app 包
import { onLoad } from '@dcloudio/uni-app';
import { onMounted, ref } from 'vue';
const list = ref([1, 2, 3]);
const addItem = () => {
list.value.push(Math.floor(Math.random() * 10) + 1);
uni.showToast({
title: '添加成功!'
});
};
onLoad((params) => {
console.log('组件加载了', params);
});
</script>
进阶用法
分包加载
分包的好处:
- 实现页面的按需加载
- 减少主包体积,突破小程序包大小限制
分包的具体步骤如下:
- 在
pages.json中配置subPackages选项,同时在 root 属性中指定分包名称,在 pages 属性中指定分包下的页面 - 新建分包目录和页面,在新建页面时勾选具体的分包
eg.pages.json分包配置示例
// 分包前
// "subPackages": [{
// "root": "pageA",
// "pages": []
// }],
// 分包后
"subPackages": [{
"root": "pageA",
"pages": [{
"path": "list/list",
"style": {
"navigationBarTextStyle": "black"
}
}]
}]
条件编译
条件编译是用特殊的注释作为标记,在编译时根据这些特殊的注释,将注释里面的代码编译到不同平台。点击查看条件编译中所有可用的平台标识
// #ifdef 平台标识
满足条件时执行的代码
// #endif
eg.三种类型条件编译示例
<template>
<view>
<!-- #ifdef H5 -->
<view class="red big">我只在H5平台显示</view>
<!-- #endif -->
<!-- #ifdef MP-WEIXIN -->
<view class="red big">我只在微信小程序中显示</view>
<!-- #endif -->
</view>
</template>
<script setup>
// #ifdef H5
console.log('H5平台才会执行的代码')
// #endif
// #ifndef H5
console.log('H5以外平台会执行的代码')
// #endif
// #ifdef H5 || MP-WEIXIN
console.log('H5平台或者微信小程序才会执行的代码')
// #endif
</script>
<style lang="scss">
.big {
font-weight: bold;
/* #ifdef H5 */
font-size: 32px;
/* #endif */
}
/* #ifdef H5 */
.red {
color: red;
}
/* #endif */
</style>
easycom组件规范
组件有三大类:内置组件、第三方组件和自定义组件(又分为全局组件和局部组件)
在 uni-app 项目中,只有 局部组件 需要先引入、注册后才能使用,其他组件可以直接使用(Vue3 引入即注册)。具体示例见 uni-app 项目与 Vue 组件引用方式对比
组件通信
在 uni-app 项目中,组件间的通信仍然采用 Vue2/Vue3 语法
eg.Vue3父子组件通信示例
<template>
<view style="padding: 10px;border: 1px solid #333;">
<view>我是父组件</view>
<Son ref="sonRef" :money="money" @change-money="changeMoney"></Son>
</view>
</template>
<script setup>
import Son from './components/son.vue'
import {
onMounted,
ref
} from "vue";
const money = ref(200)
const changeMoney = (m) => {
money.value += m
}
// ref模版引用
const sonRef = ref(null)
onMounted(() => {
sonRef.value.validate()
})
</script>
<template>
<view style="padding: 10px;border: 1px solid #333;">
<view>我是子组件</view>
<view>
老爸给的钱:{{money}}
<button size="mini" @click="getMoney">+100</button>
</view>
</view>
</template>
<script setup>
// 父传子
defineProps({
money: {
type: Number,
default: 100
}
})
// 子传父
const emit = defineEmits(['change-money'])
const getMoney = () => {
emit('change-money', 100)
}
// 暴露方法给父组件
const validate = () => {
console.log('子组件中的方法被调用了')
}
defineExpose({
validate
})
</script>
Pinia状态管理
pinia 是 Vue3 新一代状态管理工具,用来替代 Vuex
pinia-plugin-unistorage 插件在操作 pinia 中的全局状态时自动进行持久化
eg.Vue3全局状态管理示例
- 创建 Pinia 实例并注册
// main.js
import { createPinia } from 'pinia'
const pinia = createPinia()
app.use(pinia)
- 创建 Store 并导出
// stores/count.js
import { defineStore } from 'pinia'
import { computed, ref } from 'vue'
export const useCount = defineStore('count', () => {
// state
const count = ref(1)
// getters
const dbCount = computed(() => {
return count.value * 2
})
// mutations&actions
const addCount = () => {
count.value++
}
const resetCount = () => {
setTimeout(() => {
count.value = 1
}, 500)
}
// 返回全局数据和方法
return {
count,
dbCount,
addCount,
resetCount
}
},{
// 开启后对 state 的数据读写都将持久化
unistorage: {
key: 'myCount',
paths: ['count']
}
})
- 导入 Store 并使用
<!-- pages/count/count.vue -->
<template>
<view style="text-align: center;">
<view>{{store.count}}-{{store.dbCount}}</view>
<button type="primary" size="mini" @click="store.addCount">+1</button>
<button size="mini" @click="store.resetCount">重置</button>
<view>解构后的count:{{count}}</view>
</view>
</template>
<script>
import { useCount } from '@/stores/count.js'
const store = useCount()
// storeToRefs对数据进行解构处理后仍然能保持响应式
import { storeToRefs } from 'pinia'
const { count } = storeToRefs(store)
</script>