uni-app


# uni-app

安装 HBuilderX (https://dcloud.io/hbuilderx.html) 点击 APP 开发版
安装 微信开发者工具 (https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html) 选择稳定版
微信开发者工具第一次需要填路径 —— 打开文件位置,然后将位置输入到里边。且要将微信开发者工具的设置 —— 安全 —— 服务端口 开启

用 HBuilderX 的运行选项卡选来选择运行到哪里

# 文件

  • pages:用来存放 uni-app 的所有页面
  • static:用来存放静态资源
  • unpackage:用来存放最后打包输出的文件
  • App.vue:项目的根组件
  • main.js:项目的人口文件
  • manifest.json:用来配置一些应用的一些打包的东西 (配置打包之后的一些配置文件)
  • pages.json:用来设置整个项目页面的文件的存放路径以及窗口的外观
  • uni-scss:常用样式的变量

# 开发规范

  • 页面文件遵循 Vue 单文件组件规范
  • 组件标签靠近小程序规范
  • 接口能力 靠近微信小程序规范,但需将前缀 wx 替换为 uni
  • 数据绑定及事件处理同 Vue.js 规范,同时补充了 App 及页面的生命周期
  • 为兼容多端运行,建议使用 flex 布局进行开发

# 简单操作案例

  • App.vue

    <script>
      export default {
        onLaunch: function () {
          console.log("App Launch");
        },
        onShow: function () {
          console.log("App Show");
        },
        onHide: function () {
          console.log("App Hide");
        },
      };
    </script>
    
    <style lang="scss">
      /* 全局样式 */
      @import url("./static/fonts/iconfont.css");
      /* iconfont 最好使用 ~@/static/fonts/ 这种绝对路径的方式,去 iconfont.css 中修改 */
      .box1 {
        background-color: pink;
      }
    </style>
  • pages.json

    {
      "pages": [
        //pages数组中第一项表示应用启动页
        {
          "path": "pages/home/home"
        },
        {
          "path": "pages/uni-style/uni-style",
          "style": {
            "navigationBarTitleText": "样式"
          }
        },
        {
          "path": "pages/message/message",
          "style": {
            // 页面级别的配置,会将全局的配置替换掉
            "navigationBarTitleText": "信息页",
            "navigationBarBackgroundColor": "#9dc1fa", // 导航栏背景色
            // 为 h5设置特定样式
            "h5": {
              "pullToRefresh": {
                "color": "#3F536E"
              }
            }
          }
        },
        {
          "path": "pages/index/index"
        },
        {
          "path": "pages/contact/contact",
          "style": {
            "navigationBarTitleText": "联系我们"
          }
        },
        {
          "path": "pages/detail/detail",
          "style": {
            "navigationBarTitleText": "详情页"
          }
        }
      ],
      "globalStyle": {
        // 全局的配置
        "navigationBarTextStyle": "white",
        "navigationBarTitleText": "毛茸茸测试",
        "navigationBarBackgroundColor": "#87CEFA", // 导航栏背景色
        "backgroundColor": "#778899", // 下拉时的背景色
        "enablePullDownRefresh": true, //是否可以下拉
        "backgroundTextStyle": "light" // 将loading变成亮色
        // onReachBottomDistance
        // 用来设置底部距离页面多远时触发上拉触底的事件,单位只支持px
      },
      "tabBar": {
        "color": "#A0522D", // tab上的文字默认颜色
        "selectedColor": "#AEEEEE", // tab上的文字选中时的颜色
        "backgroundColor": "#FFFFFF", // tabBar 的背景色
        "borderStyle": "white", //tabbar 上边框的颜色,可选值 black/white
        "position": "bottom", //可选值 bottom、top(仅支持微信小程序)
        "list": [
          {
            "text": "首页", // tab 上按钮文字
            "pagePath": "pages/index/index", // 页面路径,必须先在 pages 中定义
            "iconPath": "static/tabs/home.png", // 未选中的图片路径
            "selectedIconPath": "static/tabs/home-active.png" // 选中的图片路径
          },
          {
            "text": "信息",
            "pagePath": "pages/message/message",
            "iconPath": "static/tabs/message.png",
            "selectedIconPath": "static/tabs/message-active.png"
          },
          {
            "text": "我们",
            "pagePath": "pages/contact/contact",
            "iconPath": "static/tabs/contact.png",
            "selectedIconPath": "static/tabs/contact-active.png"
          }
        ]
      },
      // 启动模式配置,仅开发期间生效,用于模拟直达页面的场景,如:小程序转发后,用户点击所打开的页面。
      "condition": {
        "current": 0,
        "list": [
          {
            "name": "详情页",
            "path": "pages/detail/detail",
            "query": "id=80"
          }
        ]
      }
    }
  • contact.vue

    <template>
      <view>联系我们</view>
    </template>
  • detail.vue

    <template>
      <!-- view 组件相当于 div -->
      <view>
        <view>
          <!-- text 组件 -->
          <text>不可选</text>
        </view>
        <view>
          <text selectable>这个是可选</text>
          <!-- 长按选中 -->
        </view>
        <view>
          <text selectable space="emsp" style="font-size: 16px;"
            >这个 是可选</text
          >
        </view>
        <view>
          <text>&amp;</text>
          <!-- 小程序和浏览器默认是能够解码的 -->
        </view>
        <view class="box2" hover-class="box2-active">
          <!-- hover-class 指定按下去的样式类 -->
          <!-- hover-stop-propagation 阻止事件冒泡 -->
          <!-- hover-start-time 按住后多久出现点击态,单位毫秒 -->
          <!-- hover-stay-time 手指松开后点击态保留时间 -->
          <view
            class="box"
            :hover-start-time="2000"
            :hover-stay-time="2000"
            hover-class="box-active"
            hover-stop-propagation
            >大盒子</view
          >
        </view>
    
        <button type="primary" size="mini">按钮</button>
        <!-- plain 镂空 -->
        <button type="primary" plain>按钮</button>
        <button type="primary" loading>loading</button>
    
        <!-- image 组件 -->
        <!-- mode 图片裁剪、缩放的模式 -->
        <!-- aspectFit 图片的长边能完全显示出来 -->
        <!-- aspectFill 只保证图片的短边能完全显示出来 -->
        <image src="../../static/logo.png" mode="aspectFit"></image>
      </view>
    </template>
    
    <script></script>
    
    <style>
      .box {
        width: 100px;
        height: 100px;
        background-color: orange;
      }
      .box-active {
        background-color: pink;
      }
      .box2 {
        width: 200px;
        height: 200px;
        background-color: blue;
      }
      .box2-active {
        background-color: yellow;
      }
    </style>
  • home.vue

    <template>
      <view>
        <view>基本数据绑定</view>
        <view>{{msg}}</view>
        <view>{{'你好'+'世界'}}</view>
        <view>{{1+1}}</view>
        <view>{{flag?'真的':'假的'}}</view>
    
        <image :src="imgUrl" mode=""></image>
        <view v-for="(item,index) in arr" :key="index">
          序号:{{item.id}} 标题——{{item.title}}, 使用时间——{{item.age}}
        </view>
    
        <button type="primary" @click="handleClick(100,$event)">按钮</button>
      </view>
    </template>
    
    <script>
      export default {
        data() {
          return {
            msg: "hello",
            flag: true,
            imgUrl:
              "https://img2.baidu.com/it/u=1205915504,3217808836&fm=26&fmt=auto&gp=0.jpg",
            arr: [
              {
                title: "iphone 10",
                age: "1年",
                id: 1,
              },
              {
                title: "iphone 11",
                age: "2年",
                id: 2,
              },
              {
                title: "iphone 12",
                age: "3年",
                id: 3,
              },
              {
                title: "iphone 13",
                age: "4年",
                id: 4,
              },
            ],
          };
        },
        methods: {
          handleClick(num, e) {
            console.log(num, e);
          },
        },
      };
    </script>
  • index.vue

    <template>
      <view class="content">
        <image class="logo" src="/static/logo.png"></image>
        <view class="text-area">
          <text class="title">{{title}}</text>
        </view>
      </view>
    </template>
    
    <script>
      export default {
        data() {
          return {
            title: "Hello",
          };
        },
        onLoad(options) {
          console.log("页面加载了", options);
        },
        onShow() {
          console.log("页面显示");
        },
        onReady() {
          console.log("页面初次渲染");
        },
        onHide() {
          console.log("页面隐藏了");
        },
        methods: {},
      };
    </script>
    
    <style>
      .content {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
      }
    
      .logo {
        height: 200rpx;
        width: 200rpx;
        margin-top: 200rpx;
        margin-left: auto;
        margin-right: auto;
        margin-bottom: 50rpx;
      }
    
      .text-area {
        display: flex;
        justify-content: center;
      }
    
      .title {
        font-size: 36rpx;
        color: #8f8f94;
      }
    </style>
  • message.vue

    <template>
      <view>hello-uni</view>
    </template>
  • uni-style.vue

    <template>
      <view>
        <view> 样式的学习 </view>
        <view class="box1">
          测试文字
          <text>13</text>
        </view>
        <view class="iconfont icon-tupian"> 字体图标 </view>
      </view>
    </template>
    
    <script></script>
    
    <style lang="scss">
      @import url("./a.css");
      .box1 {
        /* rpx 以750宽的屏幕为基准 */
        /* page 相当于 body节点 */
        width: 375rpx;
        height: 375rpx;
        /* 局部样式 */
        background-color: $global-color;
        text {
          color: $uni-color-success;
        }
      }
    </style>

# 生命周期

# 应用的生命周期

应用的生命周期要定义在 App.vue 中

  • onLaunch 当 uni-app 初始化完成时触发 (全局只触发一次)
  • onShow 当 uni-app 启动,或从后台进入前台显示时触发
  • onHide 当 uni-app 从前台进入后台 (隐藏时触发)
  • onError 当 uni-app 报错时触发

# 页面的生命周期

  • onLoad 监听页面加载,其参数为上个页面传递的参数,参数类型为 Object (用于页面传参)

  • onShow 监听页面显示。页面每次出现在屏幕上都触发,包括从下级页面点返回露出当前页面
    切换 tabBar 只会触发 onShow 不会触发 onLoad

  • onReady 监听页面初次渲染完成

  • onHide 监听页面隐藏

  • onUnload 监听页面卸载 (销毁)

  • onPullDownRefresh 监听用户下拉动作,一般用于下拉刷新

    <template>
      <view>
        <view> 列表页 </view>
        <view v-for="item in list"> {{item}} </view>
        <button type="default" @click="pullDown()">下拉刷新</button>
      </view>
    </template>
    
    <script>
      export default {
        data() {
          return {
            list: ["前端", "java", "ui", "测试", "大数据"],
          };
        },
        // 监听下拉刷新
        onPullDownRefresh() {
          setTimeout(() => {
            this.list = ["前端", "java", "ui"];
            uni.stopPullDownRefresh(); //关闭当前页面的下拉刷新
          }, 1000);
        },
        methods: {
          pullDown() {
            // 下拉刷新开启方式有两种
            // 1. 在 pages.json 中设置 enablePullDownRefresh 为 true
            // 2. uni.startPullDownRefresh()
            uni.startPullDownRefresh();
          },
        },
      };
    </script>
  • onReachBottom 页面滚动到底部的事件(不是 scroll-view 滚到底),常用于下拉下一页数据。具体见下方注意事项

    <template>
      <view>
        <view v-for="item in list" class="box-item"> {{item}} </view>
      </view>
    </template>
    
    <script>
      export default {
        data() {
          return {
            list: [
              "前端",
              "java",
              "ui",
              "测试",
              "大数据",
              "前端",
              "java",
              "ui",
              "测试",
              "大数据",
            ],
          };
        },
        // 在 pages.json 中设置 onReachBottomDistance 的值(数字)
        // 监听页面触底
        onReachBottom() {
          console.log("页面触底了");
          this.list = [
            ...this.list,
            ...[
              "前端",
              "java",
              "ui",
              "测试",
              "大数据",
              "前端",
              "java",
              "ui",
              "测试",
              "大数据",
            ],
          ];
        },
      };
    </script>
    
    <style>
      .box-item {
        height: 100px;
        line-height: 100px;
      }
    </style>

# 请求

使用 uni.request (obj) 进行网络请求
需要注意的是:在小程序中网络相关的 API 在使用前需要配置域名白名单
一般在 onLoad 中请求数据
也可以使用 async 和 await

  • 案例 List.vue

    <template>
      <view>
        <button type="default" @click="get">get请求</button>
      </view>
    </template>
    
    <script>
      export default {
        methods: {
          get() {
            uni.request({
              url: "https://netease-cloud-music-api-1.vercel.app/search",
              data: {
                keywords: "海阔天空",
              },
              success(e) {
                // 小程序如果请求不成功去 小程序的详情——本地设置——不校验合法域名关掉
                console.log(e);
              },
            });
          },
        },
      };
    </script>
  • 封装 uni.request ()

    • util 文件夹下 api.js

      const BASE_URL = "http://localhost:8080";
      export const myRequest = (options) => {
        return new Promise((resolve, reject) => {
          uni.request({
            url: BASE_URL + options.url,
            method: options.method || "GEt",
            data: options.data || {},
            success: (res) => {
              if (res.data.status !== 0) {
                return uni.showToast({
                  title: "获取数据失败",
                });
              }
              resolve(res);
            },
            fail: (err) => {
              uni.showToast({
                title: "请求接口失败",
              });
              reject(err);
            },
          });
        });
      };
    • 封装完之后去 main.js

      import { myRequest } from "./util/api.js";
      Vue.prototype.$myRequest = myRequest;
    • 使用

      async getSwipers(){
        const res = await this.$myRequest({
          url:'/api/getlunbo'
        })
        this.swipers = res.data.message
      }

# 数据缓存

带 sync 的是同步的,不带 sync 的是不同步的

uni.setStorage (OBJECT):存储缓存
uni.setStorageSync (KEY,DATA):存储缓存
uni.getStorage (OBJECT):获取缓存
uni.getStorageSync (KEY):获取缓存
uni.removeStorage (OBJECT):删除缓存
uni.removeStorageSync (KEY):删除缓存
uni.clearStorage ():清除本地所有缓存,禁用

  • 案例

    <template>
      <view>
        <button type="default" @click="get">get请求</button>
        <button type="default" @click="setStorage">存储数据</button>
        <button type="default" @click="getStorage">获取数据</button>
        <button type="default" @click="removeStorage">移除数据</button>
      </view>
    </template>
    
    <script>
      export default {
        methods: {
          setStorage() {
            /* uni.setStorage({
              key: "id",
              data: 80,
              success() {
                console.log("存储成功");
              },
            }); */
            uni.setStorageSync("id", 100);
          },
          getStorage() {
            /* uni.getStorage({
              key: "id",
              success(res) {
                console.log(res.data);
              },
            }); */
            const res = uni.getStorageSync("id");
            console.log(res); //100
          },
          removeStorage() {
            /* uni.removeStorage({
              key: "id",
              success() {
                console.log("删除成功");
              },
            }); */
            uni.removeStorageSync("id");
          },
        },
      };
    </script>

# 上传图片和预览

uni.chooseImage (OBJECT):从本地相册选择图片或使用相机拍照。
uni.previewImage (OBJECT):预览图片。

  • 案例

    <template>
      <view>
        <button type="default" @click="chooseImg">上传图片</button>
        <image
          v-for="item in imgArr"
          :src="item"
          @click="previewImg(item)"
        ></image>
      </view>
    </template>
    
    <script>
      export default {
        data() {
          return {
            imgArr: [],
          };
        },
        methods: {
          chooseImg() {
            uni.chooseImage({
              count: 5, // 最多可以选择的图片张数,默认9
              success: (res) => {
                // console.log(res) //成功则返回图片的本地文件路径列表 tempFilePaths
                this.imgArr = res.tempFilePaths;
              },
            });
          },
          previewImg(imgSrc) {
            uni.previewImage({
              current: imgSrc, //用来设置当前要看见的图片
              urls: this.imgArr,
              loop: true, //是否可循环预览,只支持 App
              indicator: "number", // 图片指示器样式,只支持 App
            });
          },
        },
      };
    </script>

# 条件编译跨段兼容

(https://uniapp.dcloud.io/platform?id = 跨端兼容)
写法:先注释,然后以 #ifdef 加 平台 开头,以 #endif 结尾。

  • 案例

    <template>
      <view>
        <!-- #ifdef H5 -->
        <view>我希望在h5页面看见</view>
        <!-- #endif -->
    
        <!-- #ifdef MP-WEIXIN -->
        <view>我希望在微信小程序看见</view>
        <!-- #endif -->
      </view>
    </template>
    
    <script>
      export default {
        onLoad() {
          // #ifdef H5
          console.log("h5输出");
          // #endif
          // #ifdef MP-WEIXIN
          console.log("微信小程序输出");
          // #endif
        },
      };
    </script>
    
    <style>
      /* #ifdef H5 */
      view {
        color: hotpink;
      }
      /* #endif */
    
      /* #ifdef MP-WEIXIN */
      view {
        color: orange;
      }
      /* #endif */
    </style>

# 导航跳转和传参

# 声明式跳转

navigator 组件

  • 案例

    <template>
      <view>
        声明式跳转
        <!-- 传参 -->
        <navigator url="../detail/detail?id=80&age=19">跳转至详情页</navigator>
        <!-- open-type:跳转方式 -->
        <!-- switchTab:跳转到 tabBar 页面 -->
        <navigator url="../message/message" open-type="switchTab"
          >跳转至信息页</navigator
        >
        <!-- redirect:对当前页面进行关闭,然后再跳转到下一个页面 -->
        <navigator url="../detail/detail" open-type="redirect"
          >跳转至详情页</navigator
        >
      </view>
    </template>

# 编程式跳转

  • 案例

    <template>
      <view>
        <!-- 编程式跳转 -->
        <button type="default" @click="goDetail">跳转至详情页</button>
        <button type="default" @click="goMessage">跳转至信息页</button>
        <button type="default" @click="redirectDetail">
          跳转至详情页并关闭当前页
        </button>
      </view>
    </template>
    
    <script>
      export default {
        methods: {
          goDetail() {
            uni.navigateTo({
              // url:'../detail/detail',
              // 传参
              url: "../detail/detail?id=80&age=19",
            });
          },
          goMessage() {
            // uni.switchTab 跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
            uni.switchTab({
              url: "../message/message",
            });
          },
          redirectDetail() {
            // uni.redirectTo 关闭当前页面,跳转到应用内的某个页面
            uni.redirectTo({
              url: "../detail/detail",
            });
          },
        },
      };
    </script>

# 接收参数

  • 案例

    <script>
      export default {
        // 通过 onLoad 接受上个页面传递过来的参数
        onLoad(options) {
          console.log(options);
        },
      };
    </script>

# 组件的创建使用和组件的生命周期

创建,使用以及生命周期和 Vue 相同,但是 beforeUpdate 和 updated 仅 H5 支持

# 组件通信

父传子:父组件传递 props,子组件用 props 接收

子传父:通过自定事件传递 this.$emit (‘名字’, 数据),父组件在引用的子标签上用 @名字 =‘函数’ 接收

兄弟组件之间:
uni.emit(eventName,Object)触发全局的自定义事件uni.emit(eventName,Object) 触发全局的自定义事件 uni.on (eventName,callback) 注册全局的自定义事件

  • 案例

    • a.vue

      <template>
        <view> 这是A组件<button @click="addNum">修改b组件</button> </view>
      </template>
      
      <script>
        export default {
          name: "a",
          data() {
            return {};
          },
          methods: {
            addNum() {
              uni.$emit("updateNum", 10);
            },
          },
        };
      </script>
    • b.vue

      <template>
        <view> 这是b组件的数据{{num}} </view>
      </template>
      
      <script>
        export default {
          name: "b",
          data() {
            return {
              num: 0,
            };
          },
          created() {
            uni.$on("updateNum", (num) => {
              this.num += num;
            });
          },
        };
      </script>
      
      <style></style>

# 杂项

uni.showToast():显示消息提示框

<swiper indicator-dots circular></swiper> 视图容器
<swiper-item></swiper-item>:仅可放置在 <swiper> 组件中,宽高自动设置为100%。注意:宽高100%是相对于其父组件

map 地图组件

uni.makePhoneCall() 拨打电话

<scroll-view></scroll-view> 可滚动的视图区域:比如电商的分类

<rich-text> 富文本组件,可以解析 HTML
editor 富文本编辑器
editorContext 富文本API,对富文本进行各种操作,需要先定义一个方法(method),然后触发并执行对应的API命令

uni.showLoading()

uni.showModal(OBJECT) 显示模态弹窗,可以只有一个确定按钮,也可以同时有确定和取消按钮。类似于一个API整合了 html 中:alert、confirm。

要去设置一个APPID(微信公众平台-登录-选择一个测试的-将APPID复制到manifest.json中微信小程序配置中)
如果在真机中运行不了,有可能是域名的问题,去微信公众平台-服务器域名中添加请求的主域名

uni.uploadFile(OBJECT) 上传文件
uni.uploadFile({
  url: `${this.baseURL}api/article/uploadimgs`,
  filePath: this.imgArr[0],
  name: "file",
  formData: {
    token: this.token
  },
  success: (result) => {
    console.log(JSON.parse(result.data).data)
    this.avatar = JSON.parse(result.data).data
  }
})

uni.makePhoneCall(OBJECT) 拨打电话

# uView UI 框架


文章作者: Mrr-cxh
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Mrr-cxh !
赏
 上一篇
Pc端OA管理系统解决方案 Pc端OA管理系统解决方案
OA管理系统是公司内部使用的一个管理系统,它能够能够高效,便捷的协助公司进行管理,有通讯录模块,请加模块,公告模块,任务模块,客户模块等等。通过编写OA管理系统,对ElementUI的掌握更进一步,且在项目中遇到的问题总结如下。
2021-08-09
下一篇 
Vuex Vuex
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到 Vue 的官方调试工具 devtools extension,提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能。
2021-06-08
  目录