跟我一塊兒跳進uni-app這個坑

uni-app最近超級火,各大招聘要求都把uni-app添加到任職需求,因此本身做死把公司的一個微信公衆號項目用uni-app開發。css

本文適合有Vue開發經驗者閱讀。html

1、準備工做

一、下載HBuilderX編輯器

下載HBuilderX編輯器,HBuilderX是uni-app官方推薦,其中包含可視化搭建uni-app項目、運行項目、打包編譯項目。前端

下載地址點這裏,由於我只開發微信公衆號項目,也是就H5項目,全部只下載標準版的就能夠。vue

二、解決HBuilderX編輯器沒法對less文件格式化問題

我是使用less做爲css的預編譯語言,若是你選擇的是sass做用css的預編譯語言,能夠跳過這步。html5

修改這兩個文件的配置,就能夠解決這個問題。 webpack

把紅框的內容添加進去便可。nginx

2、建立uni-app項目

在HBuilderX編輯器中建立項目很是簡單,只須要兩步。web

推薦選擇內置uni-ui項目模板,該模板已內置大量經常使用組件,並且不要刪除太多無用文件和代碼。chrome

建立好後項目的目錄結構如圖所示json

  • components 放置內置組件。
  • pages 放置開發頁面。
  • static 靜態資源。
  • App.vue 項目頁面主入口 至關Vue項目的App.vue。
  • main.js 至關Vue項目的main.js。
  • manifest.json 一些打包編譯相關的配置。
  • pages.json 配置 路由、窗口樣式、原生導航欄、底部原生tabbar。
  • uni.scss 配置uni-app內置的經常使用樣式變量。

3、啓動uni-app項目

啓動uni-app項目,在HBuilderX編輯器中也很是簡單,一步搞定。

開始編譯

編譯成功

在瀏覽器打開http://loaclhost:8080/,若是頁面以下圖所示,說明項目啓動成功。

4、開發階段

一、怎麼去除原生導航欄

我這個項目原型中是沒有原生導航欄的,因此要把它先去掉。

方法在文檔這個地方這個地方

navigationStyle設爲customtitleNView設爲false時,原生導航欄不顯示。因此去除H5端的原生導航欄有兩種方法。

都是在pages.json文件中

統一去除原生導航欄

"pages": [
    {
        "path": "pages/index/index",
        "style": {
            "navigationStyle": "custom",
            "navigationBarTitleText": "uni-ui基礎項目"
        }
    }
],
複製代碼

或者,只針對H5端去除原生導航欄。

"pages": [
    {
        "path": "pages/index/index",
        "style": {
            "h5":{
                "titleNView":false
            }
        }
    }
],
複製代碼

下圖就是去原生導航欄後的效果

二、路由配置

目前前端項目大多都是用路由來控制頁面跳轉,因此入坑一個新框架,先要屬性一下這個框架的路由怎麼配置。

uni-app的路由配置方式和小程序很像,若是你會小程序,配置起來更容易了。

uni-app項目的路由仍是pages.json中pages屬性中配置,其實上面已經應用到了。

pages屬性的值是個數組,數組每項是個json對象,每一個路由就配置在json對象中,其中path屬性是頁面路徑,style是配置頁面的樣式,咱們先不看。

在uni-app項目中,咱們通常把頁面寫在pages文件夾下,例如在pagse文件夾下添加一個叫home.vue的文件,文件內容以下

<template>
    <view>我是home頁面</view>
</template>

<script>
</script>

<style>
</style>
複製代碼

那麼咱們要在pages.json中這麼配置。

"pages": [
    {
        "path": "pages/index/index",
        "style": {
            "navigationStyle": "custom"
        }
    },
    {
        "path": "pages/home",
        "style": {
            "navigationStyle": "custom"
        }
    }
],
複製代碼

刷新頁面,你會發現瀏覽器上沒有 我是home頁面

固然這裏不是配置錯了。只是在uni-app有個規定pages節點的第一項爲應用入口頁(即首頁)。因此咱們要改一下。

"pages": [
    {
        "path": "pages/home",
        "style": {
            "navigationStyle": "custom"
        }
    },
    {
        "path": "pages/index/index",
        "style": {
            "navigationStyle": "custom"
        }
    },
],
複製代碼

這時你會發現,編譯失敗了。 緣由就是在uni-app中配置文件,每一項結束尾巴都不能加,(逗號)。,把逗號去掉,在編譯,成功後刷新頁面,就會看到home.vue這個頁面裏面的內容。

如今咱們把home.vue這個文件刪掉,在編譯,會報錯,編譯不成功。

提示咱們找不到home.vue這個文件,因此在新增/減小頁面,都須要對 pages 數組進行修改!

"pages": [
    {
        "path": "pages/index/index",
        "style": {
            "navigationStyle": "custom"
        }
    },
],
複製代碼

從新編譯,編譯成功。

三、怎麼引入阿里圖標

阿里圖標這東西,幾乎在每一個項目中都會使用到。

在Vue項目,咱們引入阿里圖標是在public文件夾下的index.html文件,經過link引入的。

可是在uni-app項目中沒有index.html文件,那麼要在哪裏引入呢。

在前面有提到過App.vue是項目頁面主入口,那咱們能夠嘗試在這裏引入。

在Vue項目中.vue文件中咱們是這麼引入樣式

<style lang="less" scoped>
    @import "./css/index.less";
</style>
複製代碼

去MDN查詢@import的用法(入口),發現 @import能夠這麼用。

@import url("chrome://communicator/skin/");
複製代碼

那麼嘗試在App.vue這麼引入阿里圖標

<style>
    @import url("https://at.alicdn.com/t/font_1811528_5xzkmbymkb7.css");
</style>
複製代碼

而後在pages/index/index.vue文件中這麼使用

<template>
    <view class="container">
        <text class="iconfont iconSIMCard"></text>
    </view>
</template>
複製代碼

刷新頁面,發現引入成功。

四、關於標籤的使用

若是你會小程序開發,這一點能夠忽略不看。

咱們以前開發微信公衆號,是用H5開發的,天然可使用html5的標籤。如經常使用的divspanimg

那麼在uni-app項目中只能用它自帶的組件標籤,如<view></view>就至關<div></div><text></text>至關<span></span>,,<image></image>至關<img/> ,具體可點這裏這裏看。

五、關於圖片路徑問題

說到這個路徑,咱們首先要搞懂幾個常識。

~表示Web應用程序根目錄,/也是表示根目錄,../表示當前目錄的上一級目錄,./表示當前目錄。

在uni-app項目引入圖片,要用內置組件標籤<image></image>,其src屬性就是配置圖片路徑,僅支持相對路徑、絕對路徑,支持 base64碼,但自定義組件裏面使用<image>時,若 src 使用相對路徑可能出現路徑查找失敗的狀況,故建議使用絕對路徑。

在項目中我是把圖片資源放在根目錄的assets/images文件夾中。若是你的頁面在pages文件夾中的路徑很深,例如

那你是否是要在頁面上這麼寫

<template>
    <view>
        <image src="../../../../assets/images/indeximg1.png"></image>
    </view>
</template>
複製代碼

其實咱們能夠利用~來改造一下。

<template>
    <view>
        <image src="~assets/images/indeximg1.png"></image>
    </view>
</template>
複製代碼

在less中使用background也能夠利用~

.home{
    background:url(~images/card/home.png) no-repeat;
}
複製代碼

這樣寫能夠避免由於少些或者多些../致使的路徑錯誤,配置起來也輕鬆。

另外咱們能夠像Vue項目中在根目錄下添加一個vue.config.js文件,來配置webpack,固然在uni-app項目中配置和在Vue項目中配置是有差別,能夠點這裏看。

咱們在vue.config.js文件配置一個路徑別名,配置方法和在Vue項目中同樣。

const path = require('path');
function resolve(dir) {
    return path.resolve(__dirname, dir)
}
module.exports = {
    configureWebpack: config => {
        return baseConfig = {
            resolve: {
                extensions: ['.js', '.vue', '.json'],
                alias: {
                    'assets': resolve('assets'),
                    'css': resolve('assets/css'),
                    'images': resolve('assets/images'),
                }
            },
        }
    },
}
複製代碼

六、關於第三方組件的使用

在uni-app中使用第三方組件都會下載到components文件夾中。因此引入第三方組件的作法和Vue項目開發同樣。

如要使用 Popup 彈出層 ,這麼引入

components: {
    uniPopup: () => import('@/components/uni-popup/uni-popup.vue'),
    uniPopupDialog: () => import('@/components/uni-popup/uni-popup-dialog.vue'),
},
複製代碼

七、關於頁面的跳轉

  • 頁面傳參

uni.navigateTo()url參數爲路徑,其後能夠帶參數,用於頁面傳參,參數在新頁面中onLoad鉤子函數接收,以下示例。

uni.navigateTo({
    url: 'test?id=1&name=uniapp'
});
複製代碼
// 在test.vue頁面接受參數
export default {
    onLoad: function (option) { //option爲object類型,會序列化上個頁面傳遞的參數
        console.log(option.id); //打印出上個頁面傳遞的參數。
        console.log(option.name); //打印出上個頁面傳遞的參數。
    }
}
複製代碼
  • 頁面棧

框架以棧的形式管理當前全部頁面,記住棧是先進後出的。

當用戶按左上角返回按鈕、安卓用戶點擊物理back按鍵時,觸發uni.navigateBack,關閉當前頁面,也就是將當前頁面出棧,返回上一個頁面,也就是返回頁面棧中最上層的頁面。固然uni.navigateBackOBJECT.delta能夠控制返回頁面棧中第幾層的頁面。能夠用getCurrentPages()能夠獲得全部頁面棧的對象。

uni.navigateTo(),保留當前頁面,將當前頁面入棧,再跳轉新的頁面。

uni.redirectTo(),關閉當前頁面,不將當前頁面入棧,再跳轉新的頁面。

uni.navigateTo(), uni.redirectTo() 只能打開非 tabBar 頁面。

不能在 App.vue 裏面進行頁面跳轉。若是用瀏覽器刷新整個頁面,會清空當前頁面棧。

八、關於消息彈窗的使用

跟服務端交互時確定要用消息彈窗,好比報錯時給出錯誤提示。uni-app框架封裝幾種消息彈窗的足跡。

uni.showToast() 顯示消息提示彈窗。 uni.hideToast() 隱藏消息提示框。 uni.showModal() 顯示模態彈窗,相似於標準 html 的消息框:alert、confirm。

十、關於加載動畫的使用

uni.showLoading() 顯示 loading 提示框, 需主動調用 uni.hideLoading() 才能關閉提示框。

uni.hideLoading() 隱藏 loading 提示框。

showToast 和 showLoading 是底層同一個,因此 showToast 和 showLoading 會相互覆蓋,而 uni.hideLoading() 也會關閉 showToast,因此注意調用順序。

十一、關於使用nginx反向代理出現Invalid Host header問題

點開manifest.json文件,在h5中devServer選項中設置"disableHostCheck": true

十二、關於使用formData格式請求接口

uni-app中是用uni.request()和服務端通訊的。其中data參數是傳給服務端的數據。

最終發送給服務器的數據是 String 類型,若是傳入的 data 不是 String 類型,會被轉換成 String。轉換規則以下:

  • 對於 GET 方法,會將數據轉換爲 query string。例如 { name: 'name', age: 18 } 轉換後的結果是 name=name&age=18。
  • 對於 POST 方法且 header['content-type'] 爲 application/json 的數據,會進行 JSON 序列化。
  • 對於 POST 方法且 header['content-type'] 爲 application/x-www-form-urlencoded 的數據,會將數據轉換爲 query string。

會發現uni.request()不能發送formData類型的數據給後端。若是要發送formData類型的數據,要用uni.uploadFile(),其做用是將本地資源上傳到開發者服務器,客戶端發起一個 POST 請求,其中 content-type 爲 multipart/form-data。

formData參數是用uni.uploadFile()上傳本地資源中其餘額外的 form data數據。

uni.uploadFile()中幾個必填的參數,如urlfilePathname能夠隨便填寫。因此可用uni.uploadFile()發起數據格式爲formData的接口請求了。

1三、關於元素尺寸的獲取

由於uni-app跨平臺時不支持引入jQuery等操做 DOM 的插件,H5 平臺能夠經過條件編譯的方式引入使用。因此在uni-app中最好不要引入jQuery,可使用uni.createSelectorQuery()建立一個SelectorQuery對象實例來獲取DOM信息。

例如要獲取<view class="p-list"></view>的高度。

const _this = this;
uni.createSelectorQuery().select(".p-list").boundingClientRect(data => {
    _this.height = data.height;
}).exec();
複製代碼

1四、關於區域上拉刷新功能實現

用uni-app中scroll-view內置組件和第三方uni-load-more組件實現。

注意scroll-view中要設定固定高度才能夠生效。

<template>
  <view class="p-list">
      <scroll-view scroll-y="true" @scrolltolower="lower" :style="{height:height+'px'}">
          <view v-for="item in list">{{item}}</view>
          <uni-load-more :status="status" iconType="auto" v-show="isShow"></uni-load-more>
      </scroll-view>
  </view>
</template>
<script>
export default {
    data(){
        return {
            current:1,//頁碼
            list:[],
            height: 0,//列表區域高度
            isShow:false,
            status: 'loading',//加載更多的狀態
        }
    },
    components: {
    	uniLoadMore: () => import('@/components/uni-load-more/uni-load-more.vue'),
    },
    mounted() {
        this.getViewHeight();
    },
    methods: {
    	getViewHeight() {
            const _this = this;
            uni.createSelectorQuery().select(".p-list").boundingClientRect(data => {
                _this.height = data.height;
            }).exec();
        },
        lower() {
            if (this.isShow) return;
            this.isShow = true;
            this.current++;
            this.getList();
        },
        getList(){
        	let data = new Object;
            data.current = this.current;
            data.size = 15;//每次加載條數
            API.getRenewRecord(data)
              .then(res => {
                  this.isShow = false;
                  if (res.code == 200) {
                      this.list = [...this.list, ...res.data]
                      if (res.data.length == 0) {
                          this.status = 'noMore';
                          this.isShow = true;
                      }
                  }
              })
              .catch(err => {
                  this.isShow = false;
              })
        }
    }
}
</script>
複製代碼

1五、關於區域下拉刷新功能實現

若是頁面頭部有固定內容,下拉刷新只能用scroll-view內置組件實現。 注意scroll-view中要設定固定高度才能夠生效。

<template>
  <view class="p-list">
      <scroll-view scroll-y refresher-enabled 
      	:refresher-triggered="triggered"
        :refresher-threshold="100" 
        @refresherrefresh="onRefresh" :style="{height:height+'px'}">
          <view v-for="item in list">{{item}}</view>
      </scroll-view>
  </view>
</template>
<script>
export default {
	data(){
    	return {
            current:1,//頁碼
            list:[],
            height: 0,//列表區域高度
            triggered:false,//下拉刷新狀態,true開啓下拉刷新,false結束下拉刷新
        }
    },
    mounted() {
        this.getViewHeight();
    },
    methods: {
    	getViewHeight() {
            const _this = this;
            uni.createSelectorQuery().select(".p-list").boundingClientRect(data => {
                _this.height = data.height;
            }).exec();
        },
        onRefresh() {
            if (this.triggered) return;
            this.triggered = true;
            this.current++;
            this.getList();
        },
        getList(){
            let data = new Object;
            data.current = this.current;
            data.size = 15;//每次加載條數
            API.getRenewRecord(data)
              .then(res => {
                  this.triggered = false;
                  if (res.code == 200) {
                      this.list = [...res.data,...this.list]
                  }
              })
              .catch(err => {
                  this.triggered = false;
              })
        }
    }
}
</script>
複製代碼

由於在微信瀏覽器中,下拉時整個頁面會下滑,而後致使scroll-view的下拉刷新卡頓。用如下方法解決

先在pages.json中開啓該頁面的下拉刷新監聽

{
   "pages":[
    	{
            "path": "testList",
            "style": {
                "enablePullDownRefresh": true
            }
        },
    ]
}
複製代碼

而後在頁面中監聽下拉刷新,一旦下拉刷新立刻執行uni.stopPullDownRefresh把下拉刷新立刻關閉。

onPullDownRefresh() {
     uni.stopPullDownRefresh()
},
複製代碼

同時在App.vue中,把下拉刷新的頁面效果隱藏

<style>
    uni-page[data-page=websms] uni-page-refresh {
        display: none;
    }
</style>
複製代碼

1六、IOS收起軟鍵盤後頁面不下滑的解決

<template>
    <view>
    	<input v-model.trim="value" @blur="handleblur"/>
    </view>
</template>
<script>
export default{
    methods: {
        handleblur() {
            uni.pageScrollTo({
                scrollTop: 0,
                duration: 0
            });
        },
    }
}
</script>
複製代碼

1七、IOS6不能撐開display:flex嵌套使用的父級高度

在父級元素加上min-height屬性。或者避免嵌套

1八、關於自定義打包後的index.html頁面

uni-app項目中默認是沒有index.html,不像Vue項目默認帶有index.html。那麼要用CND引入第三方庫,該怎麼操做。

首先在根目錄下,新建index.html文件

<!DOCTYPE html>
<html lang="zh-CN">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <title>
            <%= htmlWebpackPlugin.options.title %>
        </title>
        <script>
            document.addEventListener('DOMContentLoaded', function() {
                document.documentElement.style.fontSize = document.documentElement.clientWidth / 20 + 'px'
            })
        </script>
        <link rel="stylesheet" href="<%= BASE_URL %>static/index.<%= VUE_APP_INDEX_CSS_HASH %>.css" />
    </head>
    <body>
        <noscript>
            <strong>Please enable JavaScript to continue.</strong>
        </noscript>
        <div id="app"></div>
        <!-- built files will be auto injected -->
    </body>
</html>
複製代碼

而後在manifest.json中添加以下配置,便可。

"h5":{
    "template": "index.html",
}
複製代碼

1九、關於首屏優化的操做

開啓搖樹優化和預加載 而後在manifest.json中添加以下配置,便可。

"h5":{
    "optimization": {
        "prefetch": true,
        "preload": true,
        "treeShaking": {
            "enable": true
        }
    }
}
複製代碼

20、關於IOS首屏加載過慢的問題。

能夠看這裏

5、部署階段

一、 H5發佈

先配置

而後打包編譯

最後打包生成的文件部署到服務器上。

相關文章
相關標籤/搜索