1 基础部分总结

什么是UniApp?它有哪些特点和优势?

uni-app 是一个使用 Vue.js (opens new window) 开发所有前端应用的框架,开发者编写一套代码,可发布到iOS、Android、Web(响应式)、以及各种小程序(微信/支付宝/百度/头条/飞书/QQ/快手/钉钉/淘宝)、快应用等多个平台

uni-app简单来说是 vue的语法 + 小程序的api,它遵循Vue.js语法规范,组件和API遵循微信小程序命名,这些都属于通用技术栈,学习它们是前端必备技能,uni- app没有太多额外学习成本

uni-app 支持的手机版本最低到多少

  • Web端:uni-app没有限制,同vue2和vue3自身能支持的浏览器版本
  • 小程序端:uni-app没有限制,同该小程序自身能支持的最低平台
  • App端:
    • Vue2: Android4.4+、iOS9+。Android4.4已经是2013年发布的手机了。
    • Vue3: 支持的范围是:Android >=5 (使用nvue和vue有区别。某些老国产Android5的rom无法动态升级Android system webview,此时如果使用vue页面需搭配x5内核) , iOS >= 10

uniapp特点

  • 跨平台更多
    • 真正做到一套代码、多端发行
    • 条件编译:优雅的在一个项目里调用不同平台的特色功能
  • 运行体验更好
    • 组件、api与微信小程序一致
    • 兼容weex原生渲染
  • 通用技术栈,学习成本更低
    • vue的语法、微信小程序的api
    • 内嵌mpvue
  • 开发生态,拥抱社区
    • 支持通过npm安装第三方包
    • 支持微信小程序自定义组件及SDK
    • 兼容mpvue组件及项目
    • app端支持和原生混合编码
    • dcloud插件市场

uniapp平台功能示意图

Uniapp的目录结构组成

一个 uni-app 工程,就是一个 Vue 项目,你可以通过 HBuilderX 或 cli 方式快速创建 uni-app 工程

一个uni-app工程,默认包含如下目录及文件

    ┌─uniCloud              云空间目录,阿里云为uniCloud-aliyun,腾讯云为uniCloud-tcb(详见uniCloud)
    │─components            符合vue组件规范的uni-app组件目录
    │  └─comp-a.vue         可复用的a组件
    ├─utssdk                存放uts文件
    ├─pages                 业务页面文件存放的目录
    │  ├─index
    │  │  └─index.vue       index页面
    │  └─list
    │     └─list.vue        list页面
    ├─static                存放应用引用的本地静态资源(如图片、视频等)的目录,注意:静态资源只能存放于此
    ├─uni_modules           存放[uni_module](/uni_modules)
    ├─platforms             存放各平台专用页面的目录,详见
    ├─nativeplugins         App原生语言插件 详见
    ├─nativeResources       App端原生资源目录
    │  └─android            Android原生资源目录 详见
    ├─hybrid                App端存放本地html文件的目录,详见
    ├─wxcomponents          存放小程序组件的目录,详见
    ├─unpackage             非工程代码,一般存放运行或发行的编译结果
    ├─AndroidManifest.xml   Android原生应用清单文件 详见
    ├─main.js               Vue初始化入口文件
    ├─App.vue               应用配置,用来配置App全局样式以及监听 应用生命周期
    ├─manifest.json         配置应用名称、appid、logo、版本等打包信息,详见
    ├─pages.json            配置页面路由、导航条、选项卡等页面类信息,详见
    └─uni.scss              这里是uni-app内置的常用样式变量

static目录 使用注意

  • 编译到任意平台时,static 目录下除不满足条件编译的文件,会直接复制到最终的打包目录,不会打包编译。非 static 目录下的文件(vue、js、css 等)只有被引用时,才会被打包编译。
  • css、less/scss 等资源不要放在 static 目录下,建议这些公用的资源放在自建的 common 目录下

Vue.js和UniApp有什么关系?它们之间有什么区别?

Vue.js是一种用于构建用户界面的渐进式JavaScript框架,而UniApp是基于Vue.js的跨平台应用开发框架。UniApp在Vue.js的基础上进行了扩展,使得开发者可以使用Vue.js的开发方式和语法来编写跨平台应用。与Vue.js相比,UniApp具有以下区别:

  • 平台适配性 :Vue.js主要用于构建Web应用,而UniApp能够生成多个平台的应用,包括小程序、H5和App等。
  • 原生能力访问 :UniApp提供了对原生平台的API和能力的访问,使得开发者可以更方便地使用平台的特性和功能。
  • 组件库和UI样式 :UniApp提供了一套基于Vue.js的组件库和UI样式,方便开发者快速构建应用的界面和交互。

如何在UniApp中进行网络请求?

UniApp中可以使用uni.request方法进行网络请求。以下是一个基本的网络请求示例:

    uni.request({
      url: 'https://api.example.com/data',
      method: 'GET',
      data: {
        // 请求参数
      },
      success: function(res) {
        // 请求成功回调
        console.log(res.data);
      },
      fail: function(err) {
        // 请求失败回调
        console.log(err);
      }
    });

做个简单封装

    import store from '@/store'
    import config from '@/config'
    import { getToken } from '@/utils/auth'
    import errorCode from '@/utils/errorCode'
    import { toast, showConfirm, tansParams } from '@/utils/common'
    
    let timeout = 10000
    const baseUrl = config.baseUrl
    
    const request = config => {
      // 是否需要设置 token
      const isToken = (config.headers || {}).isToken === false
      config.header = config.header || {}
      if (getToken() && !isToken) {
        config.header['Authorization'] = 'Bearer ' + getToken()
      }
      // get请求映射params参数
      if (config.params) {
        let url = config.url + '?' + tansParams(config.params)
        url = url.slice(0, -1)
        config.url = url
      }
      return new Promise((resolve, reject) => {
        uni.request({
            method: config.method || 'get',
            timeout: config.timeout ||  timeout,
            url: config.baseUrl || baseUrl + config.url,
            data: config.data,
            header: config.header,
            dataType: 'json'
          }).then(response => {
            let [error, res] = response
            if (error) {
              toast('后端接口连接异常')
              reject('后端接口连接异常')
              return
            }
            const code = res.data.code || 200
            const msg = errorCode[code] || res.data.msg || errorCode['default']
            if (code === 401) {
              showConfirm('登录状态已过期,您可以继续留在该页面,或者重新登录?').then(res => {
                if (res.confirm) {
                  store.dispatch('LogOut').then(res => {
                    uni.reLaunch({ url: '/pages/login' })
                  })
                }
              })
              reject('无效的会话,或者会话已过期,请重新登录。')
            } else if (code === 500) {
              toast(msg)
              reject('500')
            } else if (code !== 200) {
              toast(msg)
              reject(code)
            }
            resolve(res.data)
          })
          .catch(error => {
            let { message } = error
            if (message === 'Network Error') {
              message = '后端接口连接异常'
            } else if (message.includes('timeout')) {
              message = '系统接口请求超时'
            } else if (message.includes('Request failed with status code')) {
              message = '系统接口' + message.substr(message.length - 3) + '异常'
            }
            toast(message)
            reject(error)
          })
      })
    }
    
    export default request

css 的引用

如果我们创建自定义的样式文件,例如创建一个/static/scss/test.css,想要使其在全局引用。

1、在App.vue中全局引用,每个页面都可以使用该样式。

    <style lang="scss">
      @import '@/static/scss/test.css';
    </style>

2、在index.scss中导入,每个页面都可以使用该样式。

    @import '@/static/scss/test.css';

推荐第二种方式,方便所有的样式文件在index.scss统一管理和维护。

css 的变量

css 变量描述
--status-bar-height系统状态栏高度
--window-top内容区域距离顶部的距离
--window-bottom内容区域距离底部的距离

注意:

  • var(--status-bar-height)此变量在微信小程序环境为固定25px,在App里为手机实际状态栏高度。
  • 当设置"navigationStyle":"custom"取消原生导航栏后,由于窗体为沉浸式,占据了状态栏位置。此时可以使用一个高度为var(--status-bar-height)的 view 放在页面顶部,避免页面内容出现在状态栏。
  • 由于在 H5 端,不存在原生导航栏和 tabbar,也是前端 div 模拟。如果设置了一个固定位置的居底 view,在小程序和 App 端是在 tabbar 上方,但在 H5 端会与 tabbar 重叠。此时可使用--window-bottom,不管在哪个端,都是固定在 tabbar 上方。
  • 目前 nvue 在 App 端,还不支持--status-bar-height变量,替代方案是在页面 onLoad 时通过uni.getSystemInfoSync().statusBarHeight获取状态栏高度,然后通过 style 绑定方式给占位 view 设定高度。下方提供了示例代码
    <template>
      <page-meta>
        <navigation-bar />
      </page-meta>
      <view>
        <view class="status_bar">
          <!-- 这里是状态栏 -->
        </view>
        <view>状态栏下的文字</view>
      </view>
    </template>
    <style>
      .status_bar {
        height: var(--status-bar-height);
        width: 100%;
      }
    </style>

nvue 页面获取状态栏高度

    <template>
      <view class="content">
        <view :style="{ height: iStatusBarHeight + 'px'}"></view>
      </view>
    </template>
    
    <script>
      export default {
        data() {
          return {
            iStatusBarHeight: 0,
          };
        },
        onLoad() {
          this.iStatusBarHeight = uni.getSystemInfoSync().statusBarHeight;
        },
      };
    </script>

全局变量机制

全局变量机制globalData,支持全端通用。

以下是 App.vue 中定义globalData的相关配置:

    <script>  
      export default {  
        globalData: {  
          text: 'text'  
        }
      }  
    </script>  

其他页面获取方式

    console.info(getApp().globalData.text);

修改globalData变量的方式如下:getApp().globalData.text = 'test'

注意

globalData是简单的全局变量,如果使用状态管理,请使用vuex(main.js中定义)

globalData是简单的全局变量,如果使用状态管理,请使用vuex(main.js中定义)

屏幕尺寸单位

    uni-app`支持的通用`css`单位包括`px``rpx
  • px即屏幕像素
  • rpx即响应式px,一种根据屏幕宽度自适应的动态单位。以750宽的屏幕为基准,750rpx恰好为屏幕宽度。屏幕变宽,rpx实际显示效果会等比放大 。

vue页面支持下面这些普通H5单位,但在nvue里不支持

  • rem根字体大小可以通过page-meta配置
  • vh viewpoint height,视窗高度,1vh等于视窗高度的1%
  • vw viewpoint width,视窗宽度,1vw等于视窗宽度的1%

生命周期

生命周期:应用生命周期(onLaunch→onShow→onHide)与页面生命周期的触发顺序

应用生命周期

uni-app支持如下应用生命周期函数

函数名说明
onLaunch当uni-app初始化完成时触发(全局只触发一次)
onShow当uni-app启动,或从后台进入前台显示
onHide当uni-app从前台进入后台
onError当uni-app报错时触发
onUniNViewMessage对nvue页面发送的数据进行监听
onUnhandledRejection对未处理的 Promise 拒绝事件监听函数
onPageNotFound页面不存在监听函数
onThemeChange监听系统主题变化

应用生命周期仅可在App.vue中监听,在其它页面监听无效

页面生命周期

uni-app支持如下页面生命周期函数

函数名说明
onInit监听页面初始化
onLoad监听页面加载
onShow监听页面显示
onReady监听页面初次渲染完成
onHide监听页面隐藏
onUnload监听页面卸载
onResize监听窗口尺寸变化
onPullDownRefresh监听用户下拉动作,一般用于下拉刷新
onReachBottom页面上拉触底事件的处理函数
onTabItemTap点击 tab 时触发
onShareAppMessage用户点击右上角分享
onPageScroll监听页面滚动
onNavigationBarButtonTap监听原生标题栏按钮点击事件
onBackPress监听页面返回
onNavigationBarSearchInputChanged监听原生标题栏搜索输入框输入内容变化事件
onNavigationBarSearchInputConfirmed监听原生标题栏搜索输入框搜索事件,用户点击软键盘上的“搜索”按钮时触发
onNavigationBarSearchInputClicked监听原生标题栏搜索输入框点击事件
onShareTimeline监听用户点击右上角转发到朋友圈
onAddToFavorites监听用户点击右上角收藏

onInit使用注意

  • 仅百度小程序基础库 3.260 以上支持 onInit 生命周期
  • 其他版本或平台可以同时使用 onLoad 生命周期进行兼容,注意避免重复执行相同逻辑
  • 不依赖页面传参的逻辑可以直接使用 created 生命周期替代

onReachBottom使用注意,可在pages.json里定义具体页面底部的触发距离onReachBottomDistance,比如设为50,那么滚动页面到距离底部50px时,就会触发onReachBottom事件。

如使用scroll-view导致页面没有滚动,则触底事件不会被触发。scroll-view滚动到底部的事件请参考scroll-view的文档

onPageScroll(监听滚动、滚动监听、滚动事件)参数说明:

属性类型说明
scrollTopNumber页面在垂直方向已滚动的距离(单位px)
  • onPageScroll里不要写交互复杂的js,比如频繁修改页面。因为这个生命周期是在渲染层触发的,在非h5端,js是在逻辑层执行的,两层之间通信是有损耗的。如果在滚动过程中,频发触发两层之间的数据交换,可能会造成卡顿。
    onPageScroll : function(e) { //nvue暂不支持滚动监听,可用bindingx代替
    	console.log("滚动距离为:" + e.scrollTop);
    },

onTabItemTap返回的json对象说明:

属性类型说明
indexString被点击tabItem的序号,从0开始
pagePathString被点击tabItem的页面路径
textString被点击tabItem的按钮文字
  • onTabItemTap常用于点击当前tabitem,滚动或刷新当前页面。如果是点击不同的tabitem,一定会触发页面切换。
  • 如果想在App端实现点击某个tabitem不跳转页面,不能使用onTabItemTap,可以使用plus.nativeObj放一个区块盖住原先的tabitem,并拦截点击事件。
  • 支付宝小程序平台onTabItemTap表现为点击非当前tabitem后触发,因此不能用于实现点击返回顶部这种操作
    onTabItemTap : function(e) {
      console.log(e);
      // e的返回格式为json对象: {"index":0,"text":"首页","pagePath":"pages/index/index"}
    },

onNavigationBarButtonTap参数说明:

属性类型说明
indexNumber原生标题栏按钮数组的下标
    onNavigationBarButtonTap : function (e) {
      console.log(e);
      // e的返回格式为json对象:{"text":"测试","index":0}
    }

onBackPress回调参数对象说明:

属性类型说明
fromString触发返回行为的来源:'backbutton'——左上角导航栏按钮及安卓返回键;'navigateBack'——uni.navigateBack() 方法。支付宝小程序端不支持返回此字段
    export default {
      data() {
        return {};
      },
      onBackPress(options) {
        console.log('from:' + options.from)
      }
    }

组件生命周期

uni-app组件支持的生命周期,与vue标准组件的生命周期相同。这里没有页面级的onLoad等生命周期:

函数名说明
beforeCreate在实例初始化之前被调用
created在实例创建完成后被立即调用
beforeMount在挂载开始之前被调用
mounted挂载到实例上去之后调用
beforeUpdate数据更新时调用
updated由于数据更改时调用
beforeDestroy实例销毁之前调用
destroyed实例销毁后调用

组件定义

注册

通过uni- appeasycom将组件引入精简为一步。只要组件安装在项目的components目录下,并符合components/组件名称/组件名称.vue目录结构。就可以不用引用、注册,直接在页面中使用。

    <template>
      <view>
    	<uni-badge text="1"></uni-badge>
      </view>
    </template>
    <script>
      // 这里不用import引入,也不需要在components内注册uni-badge组件。template里就可以直接用
      export default {
    	data() {
    	  return {}
    	}
      }
    </script>
  • easycom是自动开启的,不需要手动开启,有需求时可以在pages.jsoneasycom节点进行个性化设置
  • 不管components目录下安装了多少组件,easycom打包后会自动剔除没有使用的组件,对组件库的使用尤为友好。

props

props可以是数组或对象,用于接收来自父组件的数据。props可以是简单的数组,或者使用对象作为替代,对象允许配置高级选项,如类型检测、自定义验证和设置默认值。

选项类型说明
typeString、Number、Boolean、Array、Object、Date、Function、Symbol,任何自定义构造函数、或上述内容组成的数组会检查一个 prop 是否是给定的类型,否则抛出警告
defaultany为该 prop 指定一个默认值。如果该 prop 没有被传入,则换做用这个值。对象或数组的默认值必须从一个工厂函数返回
requiredBoolean定义该 prop 是否是必填项
validatorFunction自定义验证函数会将该 prop 的值作为唯一的参数代入。在非生产环境下,如果该函数返回一个 false 的值 (也就是验证失败),一个控制台警告将会被抛出

示例:子组件定义

    <template>
      <view>
    	<view>{{age}}</view>
      </view>
    </template>
    <script>
      export default {
    	props: {
    	  // 检测类型 + 其他验证
    	  age: {
    		type: Number,
    		default: 0,
    		required: true,
    		validator: function(value) {
    		  return value >= 0
    		}
    	  }
    	}
      }
    </script>

sync 修饰符

当一个子组件改变了一个prop的值时,这个变化也会同步到父组件中所绑定。.sync它会被扩展为一个自动更新父组件属性的v-on监听器。

    <!-- 父组件 -->
    <template>
      <view>
        <syncA :title.sync="title"></syncA>
      </view>
    </template>
    <script>
      export default {
        data() {
          return {
            title: "hello vue.js"
          }
        }
      }
    </script>
    <!-- 子组件 -->
    <template>
      <view>
        <view @click="changeTitle">{{title}}</view>
      </view>
    </template>
    <script>
      export default {
        props: {
          title: {
            default: "hello"
          },
        },
        methods: {
          changeTitle() {
            // 触发一个更新事件
            this.$emit('update:title', "test-app")
          }
        }
      }
    </script>

命名限制

uni-app中以下这些作为保留关键字,不可作为组件名。

a、canvas、cell、content、countdown、datepicker、div、element、embed、header、image、img、indicator、input、link、list、loading- indicator、loading、marquee、meta、refresh、richtext、script、scrollable、scroller、select、slider- neighbor、slider、slot、span、spinner、style、svg、switch、tabbar、tabheader、template、text、textarea、timepicker、transition- group、transition、video、view、web

条件编译

条件编译是用特殊的注释作为标记,在编译时根据这些特殊的注释,将注释里面的代码编译到不同平台。

写法以#ifdef#ifndef%PLATFORM%开头,以#endif结尾。

  • #ifdef:if defined 仅在某平台存在
  • #ifndef:if not defined 除了某平台均存在
  • %PLATFORM%:平台名称

仅出现在App平台下的代码

    #ifdef APP-PLUS
    需条件编译的代码
    #endif

除了H5平台,其它平台均存在的代码

    #ifndef H5
    需条件编译的代码
    #endif

H5平台微信小程序平台存在的代码

    #ifdef H5 || MP-WEIXIN
    需条件编译的代码
    #endif

注意

多个这里只有||,不可能出现&&,因为没有交集

平台名称参数

%PLATFORM%可取值如下:

生效条件
VUE3Vue3
APP-PLUSApp
APP-PLUS-NVUE或APP-NVUEApp nvue
H5H5
MP-WEIXIN微信小程序
MP-ALIPAY支付宝小程序
MP-BAIDU百度小程序
MP-TOUTIAO字节跳动小程序
MP-LARK飞书小程序
MP-QQQQ小程序
MP-KUAISHOU快手小程序
MP-JD京东小程序
MP-360360小程序
MP所有小程序
QUICKAPP-WEBVIEW所有快应用
QUICKAPP-WEBVIEW-UNION快应用联盟
QUICKAPP-WEBVIEW-HUAWEI快应用华为

注意

Vue3需要在项目的manifest.json文件根节点配置"vueVersion" : "3"

API 的条件编译

    // #ifdef  %PLATFORM%
    平台特有的API实现
    // #endif

示例,如下代码仅在App下出现:

示例,如下代码不会在H5平台上出现:


出错的图片链接: https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-uni-app- doc/06a79490-4f3c-11eb-b680-7980c8a877b8.png

除了支持单个平台的条件编译外,还支持多平台同时编译,使用||来分隔平台名称。

示例,如下代码会在AppH5平台上出现:


出错的图片链接: https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-uni-app- doc/05c1ef80-4f3c-11eb-b680-7980c8a877b8.png

组件的条件编译

    <!--  #ifdef  %PLATFORM% -->
    平台特有的组件
    <!--  #endif -->

示例,如下公众号关注组件仅会在微信小程序中出现:

    <view>
      <view>微信公众号关注组件</view>
      <view>
        <!-- #ifdef MP-WEIXIN -->
        <official-account></official-account>
        <!-- #endif -->
      </view>
    </view>

样式的条件编译

    /*  #ifdef  %PLATFORM%  */
    平台特有样式
    /*  #endif  */

注意: 样式的条件编译,无论是 css 还是 sass/scss/less/stylus 等预编译语言中,必须使用 /*注释*/ 的写法。

正确写法


出错的图片链接: https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-uni-app- doc/0bd78d80-4f3c-11eb-a16f-5b3e54966275.png

错误写法


出错的图片链接: https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-uni-app- doc/0c9c8b30-4f3c-11eb-8a36-ebb87efcf8c0.png

pages.json 的条件编译

下面的页面,只有运行至App时才会编译进去。


出错的图片链接: https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-uni-app- doc/04ecec40-4f3c-11eb-97b7-0dc4655d6e68.png

不同平台下的特有功能,以及小程序平台的分包,都可以通过 pages.json 的条件编译来更好地实现。这样,就不会在其它平台产生多余的资源,进而减小包体积。

json的条件编译,如不同平台的key名称相同,cli项目下开发者自己安装的校验器会报错,需自行关闭这些校验器对json相同key的校验规则。如果使用HBuilderX的校验器,无需在意此问题,HBuilderX的语法校验器为此优化过

static 目录的条件编译

在不同平台,引用的静态资源可能也存在差异,通过 static 的条件编译可以解决此问题,static 目录下新建不同平台的专有目录(目录名称同%PLATFORM%值域,但字母均为小写),专有目录下的静态资源只有在特定平台才会编译进去。

如以下目录结构,a.png只有在微信小程序平台才会编译进去,b.png在所有平台都会被编译。

    ┌─static                
    │  ├─mp-weixin
    │  │  └─a.png     
    │  └─b.png
    ├─main.js        
    ├─App.vue      
    ├─manifest.json 
    └─pages.json 

整体目录条件编译

如果想把各平台的页面文件更彻底的分开,也可以在test-app项目根目录创建platforms目录,然后在下面进一步创建app-plusmp- weixin等子目录,存放不同平台的文件。

platforms目录下只支持放置页面文件(即页面vue文件),如果需要对其他资源条件编译建议使用static 目录的条件编译

下拉刷新

pages.json设置对应页面enablePullDownRefresh属性,激活下拉。

    {
    	"path": "pages/pull_down/index",
    	"style": {
    		"navigationBarTitleText": "下拉测试",
    		"enablePullDownRefresh":true
    	}
    }
    <template>
      <view>
        {{ text }}
      </view>
    </template>
    
    <script>
      // 仅做示例,实际开发中延时根据需求来使用。
      export default {
        data() {
          return {
            text: 'test-app'
          }
        },
        onLoad: function(options) {
          setTimeout(function() {
            console.log('start pulldown');
          }, 1000);
          uni.startPullDownRefresh();
        },
        onPullDownRefresh() {
          console.log('refresh');
          setTimeout(function() {
            uni.stopPullDownRefresh();
          }, 1000);
        }
      }
    </script>

onPullDownRefresh

在 js 中定义onPullDownRefresh处理函数(和onLoad等生命周期函数同级),监听该页面用户下拉刷新事件。

  • 需要在pages.json里,找到的当前页面的pages节点,并在style选项中开启enablePullDownRefresh
  • 当处理完数据刷新后,uni.stopPullDownRefresh可以停止当前页面的下拉刷新

uni.startPullDownRefresh(OBJECT)

开始下拉刷新,调用后触发下拉刷新动画,效果与用户手动下拉刷新一致。

OBJECT 参数说明

参数名类型必填说明
successFunction接口调用成功的回调
failFunction接口调用失败的回调函数
completeFunction接口调用结束的回调函数(调用成功、失败都会执行)

success 返回参数说明

属性类型描述
errMsgString接口调用结果

uni.stopPullDownRefresh()

停止当前页面下拉刷新。

###数据缓存

uni.setStorage(OBJECT)

将数据存储在本地缓存中指定的 key 中,会覆盖掉原来该 key 对应的内容,这是一个异步接口。

OBJECT 参数说明

参数名类型必填说明
keyString本地缓存中的指定的 key
dataAny需要存储的内容,只支持原生类型、及能够通过 JSON.stringify 序列化的对象
successFunction接口调用成功的回调函数
failFunction接口调用失败的回调函数
completeFunction接口调用结束的回调函数(调用成功、失败都会执行)

代码示例

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

uni-uni_dcloud-dcloud_为前缀的key,为系统保留关键前缀。如uni_deviceIduni_id_token,请开发者为key命名时避开这些前缀。

uni.setStorageSync(KEY,DATA)

将 data 存储在本地缓存中指定的 key 中,会覆盖掉原来该 key 对应的内容,这是一个同步接口。

参数说明

参数名类型必填说明
keyString本地缓存中的指定的 key
dataAny需要存储的内容,只支持原生类型、及能够通过 JSON.stringify 序列化的对象

代码示例

    try {
    	uni.setStorageSync('storage_key', 'hello');
    } catch (e) {
    	// error
    }

uni.getStorage(OBJECT)

从本地缓存中异步获取指定 key 对应的内容。

OBJECT 参数说明

参数名类型必填说明
keyString本地缓存中的指定的 key
successFunction接口调用的回调函数,res = {data: key对应的内容}
failFunction接口调用失败的回调函数
completeFunction接口调用结束的回调函数(调用成功、失败都会执行)

代码示例

    uni.getStorage({
    	key: 'storage_key',
    	success: function (res) {
    		console.log(res.data);
    	}
    });

uni.getStorageSync(KEY)

从本地缓存中同步获取指定 key 对应的内容。

参数说明

参数名类型必填说明
keyString本地缓存中的指定的 key

代码示例

    try {
    	const value = uni.getStorageSync('storage_key');
    	if (value) {
    		console.log(value);
    	}
    } catch (e) {
    	// error
    }

uni.getStorageInfo(OBJECT)

异步获取当前 storage 的相关信息。

OBJECT 参数说明

参数名类型必填说明
successFunction接口调用的回调函数,详见返回参数说明
failFunction接口调用失败的回调函数
completeFunction接口调用结束的回调函数(调用成功、失败都会执行)

success 返回参数说明

参数名类型说明
keysArray<String>当前 storage 中所有的 key
currentSizeNumber当前占用的空间大小, 单位:kb
limitSizeNumber限制的空间大小, 单位:kb

代码示例

    uni.getStorageInfo({
    	success: function (res) {
    		console.log(res.keys);
    		console.log(res.currentSize);
    		console.log(res.limitSize);
    	}
    });

uni.getStorageInfoSync()

同步获取当前 storage 的相关信息。

代码示例

    try {
    	const res = uni.getStorageInfoSync();
    	console.log(res.keys);
    	console.log(res.currentSize);
    	console.log(res.limitSize);
    } catch (e) {
    	// error
    }

uni.removeStorage(OBJECT)

从本地缓存中异步移除指定 key。

OBJECT 参数说明

参数名类型必填说明
keyString本地缓存中的指定的 key
successFunction接口调用的回调函数
failFunction接口调用失败的回调函数
completeFunction接口调用结束的回调函数(调用成功、失败都会执行)

代码示例

    uni.removeStorage({
    	key: 'storage_key',
    	success: function (res) {
    		console.log('success');
    	}
    });

uni.removeStorageSync(KEY)

从本地缓存中同步移除指定 key。

参数说明

参数名类型必填说明
keyString本地缓存中的指定的 key

代码示例

    try {
    	uni.removeStorageSync('storage_key');
    } catch (e) {
    	// error
    }

uni.clearStorage()

清理本地数据缓存。

代码示例

    uni.clearStorage();

uni.clearStorageSync()

同步清理本地数据缓存。

代码示例

    try {
    	uni.clearStorageSync();
    } catch (e) {
    	// error
    }

自定义头部

pages.json 中设置去掉原生头部

navigationStyle设为customtitleNView设为false时,原生导航栏不显示。

    {
      "pages": [{
          "path": "pages/index/index",
          "style": {
            "navigationBarTitleText": "首页",
            // 单个页面设置
            "navigationStyle": "custom"
            /* "app-plus": {
            	"titleNView": false
            } */
          }
        },
        {
          "path": "pages/index/list-news",
          "style": {
            "navigationBarTitleText": "新闻"
          }
        }
      ],
      "globalStyle": {
        "navigationBarTextStyle": "black",
        "navigationBarTitleText": "uni-app",
        "navigationBarBackgroundColor": "#F8F8F8",
        "backgroundColor": "#F8F8F8",
        // 全局设置
        "navigationStyle": "custom"
        /* "app-plus":{
        	"titleNView":false
        } */
      }
    }

状态栏 占位div

非H5端,手机顶部状态栏区域会被页面内容覆盖。这是因为窗体是沉浸式的原因,即全屏可写内容。uni-app提供了状态栏高度的css变量--status- bar-height,如果需要把状态栏的位置从前景部分让出来,可写一个占位div,高度设为css变量。

使用css方式进行控制

    <template>
      <view>
        <view class="status_bar">
          <!-- 这里是状态栏 -->
        </view>
        <view> 状态栏下的文字 </view>
      </view>
    </template>
    <style>
      .status_bar {
        height: var(--status-bar-height);
        width: 100%;
      }
    </style>

使用js方式进行控制

    <template>
      <view>
        <view :style="'height:'+statusHeight+'px'">
          <!-- 这里是状态栏 -->
        </view>
        <text> 状态栏下的文字 </text>
      </view>
    </template>
    <script>
      export default {
        data() {
          return {
            statusHeight: 0
          }
        },
        onLoad() {
          this.statusHeight = plus.navigator.getStatusbarHeight();
        }
      }
    </script>

事件监听注册

uniapp 提供了事件的监听注册以及触发,注册的事件都是 App 全局级别的,可以很方便的跨任意组件,页面,nvue,vue 等。

相关注册或触发函数

uni.$emit(eventName,OBJECT)

触发全局的自定义事件,附加参数都会传给监听器回调函数。

属性类型描述
eventNameString事件名
OBJECTObject触发事件携带的附加参数

代码示例

    uni.$emit('update',{msg:'页面更新'})

uni.$on(eventName,callback)

监听全局的自定义事件,事件由uni.$emit触发,回调函数会接收事件触发函数的传入参数。

属性类型描述
eventNameString事件名
callbackFunction事件的回调函数

代码示例

    uni.$on('update',function(data){
      console.log('监听到事件来自 update ,携带参数 msg 为:' + data.msg);
    })

uni.$once(eventName,callback)

监听全局的自定义事件,事件由uni.$emit触发,但仅触发一次,在第一次触发之后移除该监听器。

属性类型描述
eventNameString事件名
callbackFunction事件的回调函数

代码示例

    uni.$once('update',function(data){
      console.log('监听到事件来自 update ,携带参数 msg 为:' + data.msg);
    })

uni.$off([eventName, callback])

移除全局自定义事件监听器。

属性类型描述
eventNameArray<String>事件名
callbackFunction事件的回调函数
  • 如果uni.$off没有传入参数,则移除App级别的所有事件监听器;
  • 如果只提供了事件名(eventName),则移除该事件名对应的所有监听器;
  • 如果同时提供了事件与回调,则只移除这个事件回调的监听器;
  • 提供的回调必须跟$on的回调为同一个才能移除这个回调的监听器

代码示例

$emit$on$off常用于跨页面、跨组件通讯,这里为了方便演示放在同一个页面

    <template>
      <view class="content">
        <view class="data">
          <text>{{val}}</text>
        </view>
        <button type="primary" @click="comunicationOff">结束监听</button>
      </view>
    </template>
    
    <script>
      export default {
        data() {
          return {
            val: 0
          }
        },
        onLoad() {
          setInterval(() => {
            uni.$emit('add', {
              data: 2
            })
          }, 1000)
          uni.$on('add', this.add)
        },
        methods: {
          comunicationOff() {
            uni.$off('add', this.add)
          },
          add(e) {
            this.val += e.data
          }
        }
      }
    </script>
    
    <style>
      .content {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
      }
    
      .data {
        text-align: center;
        line-height: 40px;
        margin-top: 40px;
      }
    
      button {
        width: 200px;
        margin: 20px 0;
      }
    </style>
  • uni.$emit、 uni.$on 、 uni.$once 、uni.$off 触发的事件都是 App 全局级别的,跨任意组件,页面,nvue,vue 等
  • 使用时,注意及时销毁事件监听,比如,页面 onLoad 里边 uni.$on 注册监听,onUnload 里边 uni.$off 移除,或者一次性的事件,直接使用 uni.$once 监听
  • 注意 uni.$on 定义完成后才能接收到 uni.$emit 传递的数据

场景案例

我们假设一个场景,进入app,是未登陆状态,需要在我的页面点击登陆,进入登陆页面进行登陆。登陆成功之后,返回到我的页面,实时显示登陆后的用户信息。

监听事件

在用户中心页面 监听事件。因为事件监听是全局的,所以使用uni.$on,需要使用uni.$off移除全局的事件监听,避免重复监听。

    <template>
      <view class="content">
        <navigator url="/pages/login/index" hover-class="navigator-hover">
          <button type="default">点我登录</button>
        </navigator>
        <view v-if="usnerInfo !== null">
          <view>
            用户token:{{usnerInfo.token}},用户昵称:{{usnerInfo.nickName}}
          </view>
        </view>
      </view>
    </template>
    
    <script>
      export default {
        data() {
          return {
            usnerInfo: null
          }
        },
        onLoad() {
          // 监听事件
          console.log('on login....');
          uni.$on('login', (uinfo) => {
            this.usnerInfo = uinfo;
          })
        },
        onUnload() {
          // 移除监听事件
          console.log('off login....');
          uni.$off('login');
        },
        methods: {
    
        }
      }
    </script>

触发事件

进入登陆页面,触发事件。使用uni.$emit触发事件后,对应的uni.$on就会监听到事件触发,在回调中去执行相关的逻辑。

    <template>
      <view>
        <button type="default" @click="login">登录</button>
      </view>
    </template>
    
    <script>
      export default {
        data() {
          return {};
        },
        methods: {
          login() {
            // 假设用户登录成功,此时调用emit方法触发监听事件,刷新用户登录信息
            uni.$emit('login', {
              token: 'user123456',
              nickName: 'wk123',
            });
          }
        }
      }
    </script>

基本上述场景均可以实现,本质上就是一个页面通知另一个面我发生了变化,你需要处理一下。绝大部分页面的通讯都可以使用uni.$emituni.$onuni.$onceuni.$off四个事件完成

Last Updated:
Contributors: leeguooooo