uni-app

205 阅读5分钟

运行uniapp

  • HBuilderX下载
  • 浏览器中运行
    • HBuilderX中,选中项目,点击运行(工具栏)-> 运行到浏览器 -> Chrome
  • 微信开发者工具
    • 首次需配置
      • 开启服务端口:微信开发者工具中,点击设置(工具栏) -> 安全设置 -> 打开服务端口
      • 配置微信开发者工具的安装路径:HBuilderX中,点击运行(工具栏)-> 运行到小程序模拟器 -> 微信开发者工具 -> 填写微信开发者工具的安装路径
    • HBuilder中,点击运行(工具栏)-> 运行到小程序模拟器 -> 微信开发者工具
  • 运行 App 到手机或模拟器
    • mumu模拟器下载
    • adb调试桥(命令行工具)
      • 功能:连接手机设备、安装App、热更新、调试打印log等
      • 下载
      • 配置,或者直接在HBuilderX中下载插件
        • 配置adb环境变量
          • 将安装目录配置到环境变量 path
          • cmd,敲入 adb 验证是否配置成功
        • HBuilderX中配置adb
          • HBuilder中,点击运行(工具栏)-> 运行到手机或模拟器 -> ADB路径设置
    • 配置mumu模拟器
      • cmd命令行,adb connect 127.0.0.1:7555,mumu的默认运行端口7555
      • cmd命令行,adb devices,查看是否连接成功
    • 运行项目
      • HBuilder中,点击运行(工具栏)-> 运行到手机或模拟器 -> 运行到Android App基座

uni-app概述

局部样式和全局样式

  • 全局样式:uni.css,App.vue
  • 局部样式:pages里的vue文件都是,相当于<style scoped></style>(uni-app的style标签不写scoped属性)

app.vue 和 pages 里的页面

<!-- # App.vue -->
<script>
    export default {
        // 1. 应用生命周期
        onLaunch: function() {
            console.log('App Launch')
        },
        onShow: function() {
            console.log('App Show')
        },
        onHide: function() {
            console.log('App Hide')
        },
        // 2. 定义全局数据
        globalData: {
            name: 'shan',
            age: 16,
        }
    }
</script>

<style>
    /* 3.每个页面公共css */
    .title {
        color: lightcoral;
    }
</style>
<!-- # pages/index/index.vue -->
<template>
    <view class="content">
        <text class="title">{{title}}</text>
    </view>
</template>

<script>
    export default {
        data() {
            return {
                title: 'Hello'
            }
        },
        // 页面生命周期
        onLoad() {
            console.log("this->", this);  // vue 的实例

            // 全局数据 globalData
            const app = getApp() // 当前应用实例
            console.log("globalData->", app.globalData) 

            // 当前页面路由
            const pages = getCurrentPages() // 当前页面栈实例
            console.log("route->", pages[pages.length - 1].route)
        },
        // vue 组件的生命周期
        beforeCreate() {
            console.log('beforeCreate')
        },
        created() {
            console.log('created')
        },
        methods: {}
    }
</script>

<style>
    .title {
        font-size: 36rpx;
    }
</style>

打印结果

其他页面

  • page.json 全局页面配置,类似小程序 app.json
  • manifest.json 跨端配置

uni-app 组件

内置组件

  • view
  • text
  • button
  • image
  • scrollview
  • swiper

尺寸单位 rpx

  • uniapp支持通用css单位,px/rpx(推荐)/vh/vw
  • rpx(responsive pixel),可根据屏幕宽度自适应
  • 规定屏幕宽为750rpx
  • 若设计稿标准为iPhone6(760px),一个100px的宽度,在uniapp的宽度计算为:100px/760px = uniapp宽度/760rpx,即1rpx=1px

条件编译

// #ifdef H5
console.log('1111111111111')
// #endif

其他

  • 样式导入 @import
  • 背景图片
    • 小程序不支持本地图片,支持base64/线上图片
    • uniapp支持小于40kb的本地图片
  • 字体图标

扩展组件(uni-ui)

  • 安装
    • 官网按需下载,自动导入
    • 在uni.scss可以改uni-ui提供的内置scss变量
  • uni-from
  • 更改组件样式
    • global(选择器) {}!important 全局
    • deep(选择器) {}!important 局部

路由

路由(组件)

<navigator url="/pages/index/index">
    <button type="default">index</button>
</navigator>
<navigator url="/pages/detail/detail" open-type="redirect">
    <button type="default">当前页打开 detail</button>
</navigator>
<navigator url="/pages/cart/cart" open-type="switchTab">
    <text>cart tab</text>
</navigator>
  • open-type 属性
    • navigate(默认),对应 uni.navigateTo 的功能
    • redirect,对应 uni.redirectTo 的功能
    • switchTab,对应 uni.switchTab 的功能
    • navigateBack,对应 uni.navigateBack 的功能
    • reLaunch,对应 uni.reLaunch 的功能,抖音小程序与飞书小程序不支持

路由(API)

gotoPage() {
    uni.navigateTo({ // 新页面入栈,只能非tab页
        url: "/pages/detail/detail"
    })

    // uni.redirectTo({ // 当前页面出栈,新页面入栈,只能非tab页
    // 	url: "/pages/detail/detail"
    // })

    // uni.navigateBack({ // 页面不断出栈,直到返回目标页,只能非tab页
    // 	url: "/pages/detail/detail"
    // })

    // uni.switchTab({ // 页面全出栈,只留下新的tab页,只能tab页
    // 	url: "/pages/cart/cart"
    // })

    // uni.reLaunch({ // 重加载,页面全出栈,只留下新页面,所有页面
    // 	url: "/pages/detail/detail"
    // })
}

页面之间通讯

url(query)和eventChannel

  • A页面 -> B页面, B页面 -> A页面
// # home.vue
methods: {
    gotoDetail() {
        uni.navigateTo({ // 新页面入栈,只能非tab页
            url: "/pages/detail/detail?name=shan&id=123",
            events: {
                // 为指定事件添加一个监听器,获取被打开页面传送到此页面的数据(B -> A)
                acceptDataFromOtherPage: function(data) {
                    console.log('otherPage', data)
                }
            },
            success(res) {
                // 通过eventChannel向被打开页面传送数据(A -> B)
                res.eventChannel.emit('acceptDataFromHomePage', {
                    data: "home data"
                })
            }
        })
    }
    
// # detail.vue
onLoad(option) {
    // url(A -> B)
    const urlQuery = option
    console.log('urlQuery', urlQuery)
    const eventChannel = this.getOpenerEventChannel();
    // 触发上一页面的监听函数,将参数传至上一页面(B -> A)
    eventChannel.emit('acceptDataFromOtherPage', {
        data: 'fromDetailPage'
    });
    // 监听acceptDataFromHomePage事件,获取上一页面通过eventChannel传送到当前页面的数据(A -> B)
    eventChannel.on('acceptDataFromHomePage', function(data) {
        console.log('formHomePage', data)
    })
},
// #vue3_detail1
<script setup>
    import { ref, getCurrentInstance } from 'vue';
    import { onLoad } from '@dcloudio/uni-app'

    const $instance = ref(getCurrentInstance().proxy) // vue2 的 this
    // 页面生命周期
    onLoad(() => {
        const eventChannel = $instance.value.getOpenerEventChannel()
        eventChannel.on('acceptDataFromHomePage', function(data) {
            console.log('formHomePage111', data)
        })
    })
</script>

image.png

  • 特殊字符时需要对参数进行编码encodeURIComponent(JSON.stringify(item))
<navigator :url="'/pages/test/test?item='+ encodeURIComponent(JSON.stringify(item))"></navigator>
// 在test.vue页面接受参数
onLoad: function (option) {
    const item = JSON.parse(decodeURIComponent(option.item));
}

事件总线

uni.$emit(eventName, Object)
uni.$on(eventName, callback)
uni.$once(eventName, callback)  // 只监听一次
uni.$off(eventName, callback)  // $on,记得$off销毁

globalData

  • App.vue

本地数据存储

  • uni.setStorage 异步
  • uni.setStorageSync 同步
  • uni.getStorage
  • uni.getStorageSync
  • uni.getStorageInfo
  • uni.getStorageInfoSync
  • uni.removeStorage
  • uni.removeStorageSync
  • uni.clearStorage
  • uni.clearStorageSync
uni.setStorage({
    key: 'storage_key',
    data: 'hello',
    success: function () {
        console.log('success');
    }
});

Vuex和pinia,状态管理库

常用的页面生命周期

<script setup>
    import { ref, onMounted } from 'vue';
    import {
        onLoad, // 接受上页的参数,联网取数据,更新data
        onShow, // 当前页面的activity 实例创建完成
        onReady, // onReady后,页面元素就可以自由操作了,比如ref获取节点
        onHide,
        onUnload,
        onPullDownRefresh,
        onReachBottom
    } from '@dcloudio/uni-app'
    // 页面生命周期
    onLoad(() => { console.log('onLoad') })
    onShow(() => { console.log('onShow') })
    onReady(() => { console.log('onReady') })
    onUnload(() => { console.log('onUnload') })
    onHide(() => { console.log('onHide') })
    onReachBottom(() => { console.log('onReachBottom')})
    onPullDownRefresh(() => {
        console.log('onPullDownRefresh')
        setTimeout(()=>{
            uni.stopPullDownRefresh()
        }, 1000)
    })

    uni.setStorage({
        key: 'storage_key',
        data: 'hello',
        success: function () {
            console.log('success');
        }
    });
</script>

自定义组件

  • vue标准组件需要创建、引用、注册
  • easycom组件,符合根目录/components/s-button/s-button.vue的目录结构,可以在页面中直接使用
// 和写vue组件大体一致
// 直接使用
<view>
    <s-button type="success" @onBtnClick="handleClick">button</s-button>
    <s-button type="default" @onBtnClick="handleClick">button</s-button>
</view>
 
// #s-button.vue
<template>
    <view :class="['s-btn', type]" @click="handleBtnClick">
        <slot></slot>
    </view>
</template>

<script setup>
    const props = defineProps({
        type: String,
        default: 'default'
    })

    const emit = defineEmits(['onBtnClick'])
    function handleBtnClick() {
        console.log('buttonclick')
        emit('onBtnClick')
    }
</script>

<style>
    .s-btn {
        text-align: center;
        line-height: 60rpx;
        height: 60rpx;
        margin: 10rpx;
    }
    .default {
        background-color: aquamarine;
    }
    .success {
        background-color: lightgreen
    }
</style>

pinia

  • uni-app内置了pinia
// main.js
import App from './App'
import { createSSRApp } from 'vue'
import * as Pinia from 'pinia';

export function createApp() {
  const app = createSSRApp(App)
  app.use(Pinia.createPinia());
  return {
    app,
	Pinia,
  }
}

// stores/counter.js
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', { // counter,名称要有唯一性
    state: () => {
        return { count: 100 }
    },
    actions: { // 同步、异步都可写
        increment() { this.count ++; },
        decrement() { this.count --; }
    }
})

// pages/counter/counter.vue
<template>
    <view>
        <button @click="handleAdd">+</button>
        <button @click="handleSub">-</button>
        <text>{{ counter.count }}</text>
    </view>
</template>

<script setup>
    import { useCounterStore } from '@/stores/counter.js'
    const counter = useCounterStore()

    function handleAdd() {
        counter.increment()
    }
    function handleSub() {
        counter.decrement()
    }
</script>