2020年uniapp學習手記-基礎篇,和我一起學uniapp

lookroot發表於2020-10-09

uniapp基礎部分

有文件還看什麼教程?

官網文件非常的詳細,但是如果沒有接觸過的新人看文件其實是沒法學的,因為他不知道要完成一個開發,需要學習那些知識點,而且如何正確的使用文件也不清楚

本次內容主要是為後面的實戰課打基礎,如果你會的話完全可以不看,也大可不必說什麼風言風語,你會不代表別人都會,說這種話真的讓人挺難受的

其實我昨天晚上凌晨已經錄了一套視訊是完全現場看文件錄的,效果不好,還是得寫個簡單的文件來錄(肝?)

本次的內容主要就是帶你看文件,沒錯就是看文件,讓你學會看文件,並且有個整體的認知

開發工具

首先uniapp可以使用命令列的方式開發,然後選擇你喜歡的開發工具,但是大可不必,HBuilder X完全能滿足需求,記得下載app開發版本的

官方稱可以同時編譯十個平臺,但是如果你想讓每個平臺都是同樣的體驗的話,估計是要花很多的功夫的;即使你只需要開發微信小程式一個平臺,uniapp也是一個很好的選擇

image-20201005012909579

我希望你是使用chrome瀏覽器的,新edge瀏覽器也可以,如果你對瀏覽器除錯感興趣的話還可以看我總結的瀏覽器除錯技巧

你還可以在電腦上安裝一個 Android的虛擬機器用來做安卓端的除錯,安裝小程式開發工具(一般安裝微信的就可以了)

前置知識

你最好能有vuejs的基礎知識,如果沒有也別怕,可以跟著我的vue基礎教程學習,花不了多少時間

認識一下官方文件

image-20201005224206838

  • 介紹 ;這個部分的內容更像一個說明書,可以看一下
  • 框架;這個部分更多的是關於整個專案的配置方面的東西
  • 元件;專案中的頁面實現主要看這個部分
  • API;專案中的邏輯功能主要看這個部分
  • unicloud;小公司利器,後面會專門講

意圖

首先你一定要明確自己的意圖,使用uniapp的目的,不能為了會什麼技術去做什麼東西,要為了實現什麼功能去學習技術

  • 如果你是想開發精美的移動app 你完全可以使用原生就行開發 flutter也是更好的選擇

  • 如果你只是想開發小程式,uniapp也是一個非常好的選擇

  • 如果你想快速上線一個 小程式+app的應用,你需要提前做好填坑的心理準備

    • uniapp繼承了weex那一套,再app端你可以使用nvue渲染,純原生渲染

我們認識一下專案

image-20201005013906497

開啟manifest.json可以對我們的專案進行配置,不過目前你也不能配置個啥,可以設定一下h5網頁的名稱或者是app端的圖示等等,後面需要配置的地方再說

page

pages.json是專案的頁面配置,可能是我們前面最多配置的地方,pages陣列裡面放置的就是一個個頁面,第一項配置就是預設開啟程式的頁面,後面如果我們除錯哪個頁面,為了方便可以把他放到第一個位置

tabBar

很多應用基本的標配

image-20201005014342729

配置它也很簡單,我們先建立三個頁面來試一試,在pages資料夾滑鼠右鍵可以選擇新建頁面

image-20201005014439554

根據這個方式我們新建content、list這兩個頁面,每個頁面的檔案中我們就隨便寫個文字區別就行了,uniapp的頁面結構和vuejs是幾乎一樣的

image-20201005014611690

然後我們在static目錄下放置一個圖示icon.png

page.json中配置我們的tabBar,可以通過colorselectedColor來設定預設和選中的字型顏色,list裡面就是放置的具體每個選項,每個選項裡面需要配置pagePath頁面連結,iconPath預設圖selectedIconPath選中以後的圖示,text文字

"tabBar": {
	"color": "#7A7E83",
	"selectedColor": "#f55f25",
	"borderStyle": "black",
	"backgroundColor": "#ffffff",
	"list": [{
			"pagePath": "pages/index/index",
			"iconPath": "static/logo.png",
			"selectedIconPath": "static/icon.png",
			"text": "主頁"
		},
		{
			"pagePath": "pages/list/list",
			"iconPath": "static/logo.png",
			"selectedIconPath": "static/icon.png",
			"text": "列表"
		}, {
			"pagePath": "pages/content/content",
			"iconPath": "static/logo.png",
			"selectedIconPath": "static/icon.png",
			"text": "內容"
		}
	]
}

image-20201005015111623

看下效果

image-20201005015136609

導航欄

文件

當頁面的預設導航欄不滿足我們的需求的時候,我們可以自定義導航欄,只需要在這個頁面的page.json欄目設定一下就可以了

{
	"path": "pages/index/index",
	"style": {
		"navigationBarTitleText": "uni-app",
		"navigationStyle":"custom"
	}
},

此時我們的導航欄就不見了,可以使用官方的元件,也可以自己實現,詳情看下方的使用元件

使用元件

uniapp的生態還是不錯的,除了官方的 uni-ui外掛市場還有很多現成的東西

我們下載一個這個外掛

image-20201005223810843

新版本的uniapp是不需要做任何配置可以直接使用第三方元件的

image-20201005010056921

直接在頁面中使用這個外掛,然後看看效果

<uni-nav-bar left-icon="back" left-text="返回" right-text="選單" title="導航欄元件"></uni-nav-bar>

image-20201005223931902

使用微信小程式的元件

文件

有時候你需要的元件,uniapp外掛市場沒有,但是微信小程式元件裡面有怎麼辦呢,uniapp也是可以使用小程式元件的

在根目錄新建一個wxcomponents資料夾,裡面繼續建立一個wxcomdemo資料夾

建立以下幾個檔案

index.js

Component({
  properties: {
    // 這裡定義了innerText屬性,屬性值可以在元件使用時指定
    innerText: {
      type: String,
      value: 'default value',
    }
  },
  data: {
    // 這裡是一些元件內部資料
    someData: {}
  },
  methods: {
    // 這裡是一個自定義方法
    customMethod: function(){}
  }
})

index.json

{
  "component": true
}

index.wxml

<view class="inner">
  {{innerText}}
</view>
<slot></slot>

index.wxss

/* 這裡的樣式只應用於這個自定義元件 */
.inner {
  color: red;
}

以上這幾個檔案便組成了一個標準的小程式元件了,這個元件的意思就是傳入一個字串,然後展示它字型為紅色,下面來使用這個元件吧!

在需要使用這個元件的頁面的page.json項配置

"path": "pages/index/index",
"style": {
	"navigationBarTitleText": "uni-app",
	"navigationStyle": "custom",
	"usingComponents": {
		"wxcomdemo": "/wxcomponents/wxcomdemo/index"
	}
}

然後在這個頁面中使用

<wxcomdemo inner-text="Some text"></wxcomdemo>

此時我們看看效果

image-20201005231057422

構建一個todolist

使用color ui

因為懶得寫樣式,我們引入colorui,匯入專案以後複製根目錄的 /colorui 資料夾到你的根目錄

App.vue引入關鍵Css

<style>
    @import "colorui/main.css";
    @import "colorui/icon.css";
</style>

平時開發的時候需要什麼效果,我們直接將這個示例專案執行起來,然後去複製它頁面中的程式碼就行

列表渲染

比如這個列表左滑就適合我們的頁面

image-20201006141045779

直接複製過來做下修改,首先定義幾個需要使用的屬性

staticTodoList: [{
		_id: 1,
		_name: "第一件事",
		_status: false
	},
	{
		_id: 2,
		_name: "第二件事",
		_status: true
	},
	{
		_id: 3,
		_name: "第三件事",
		_status: false
	}
],
todoList: [],
modalName: null,
listTouchStart: 0,
listTouchDirection: null,

onload的時候我們要初始化資料,這個staticTodoList就是我們模擬的靜態資料

onLoad() {
	this.todoList = this.staticTodoList;
},

然後使用剛剛複製的頁面程式碼渲染它

<view class="cu-item" 
:class="modalName=='move-box-'+ index?'move-cur':''" 
v-for="(todo,index) in todoList" 
:key="index"
 @touchstart="ListTouchStart" 
 @touchmove="ListTouchMove" 
 @touchend="ListTouchEnd" 
 :data-target="'move-box-' + index">
	<view class="content" >
		<view class="text-grey">{{todo._name}}</view>
	</view>
	<view class="action">
		<switch :checked="todo._status"  :data-_id="todo._id" />
	</view>
	<view class="move">
		<view class="bg-red" >刪除</view>
	</view>
</view>

它的頁面中還定義了幾個事件,我們也拷貝過來

ListTouchStart(e) {
	this.listTouchStart = e.touches[0].pageX
},
ListTouchMove(e) {
	this.listTouchDirection = e.touches[0].pageX - this.listTouchStart > 0 ? 'right' : 'left'
},
ListTouchEnd(e) {
	if (this.listTouchDirection == 'left') {
		this.modalName = e.currentTarget.dataset.target
	} else {
		this.modalName = null
	}
	this.listTouchDirection = null
},

看下效果

image-20201006141627428

刪除和切換(小技巧?)

<view class="action" >
	<switch :checked="todo._status" @change="switchTodo" :data-_id="todo._id" />
</view>
<view class="move">
	<view class="bg-red" @click="del(todo._id)">刪除</view>
</view>

這兩個事件也非常簡單,主要是狀態切換這裡有個小問題,@change只能傳遞當前的是否選中的值,不能傳遞當前項的id值,這就沒法處理資料,所以可以給這個節點繫結一個:data-_id="todo._id",然後通過e.target.dataset._id就能取出這個id值了!

switchTodo(e) {
	const status = e.target.value;
	const _id = e.target.dataset._id;
	this.todoList = this.todoList.map(todo => {
		if (todo._id == _id) {
			todo._status = status;
		}
		return todo;
	})
	uni.showToast({
		title: status ? "已完成" : "已取消",
		icon: status ? "success" : "none"
	})
},
del(_delId) {
	this.todoList = this.todoList.filter(todo => {
		return todo._id != _delId
	});
},

mixin

vue中的mixin同樣的也可以在這裡面使用,不知道這個東西的朋友,可以理解為公用邏輯抽離,需要使用的地方直接引入就可以了

比如Toast這個訊息通知經常用,我們可以封裝一下,新建一個mixin/message.js

module.exports = {
	methods: {
		toast(message, duration, success) {
			uni.showToast({
				title: message,
				icon: success ? "success" : "none",
				duration: duration
			})
		},
	},
};

使用它

import message from "@/mixin/message.js"
export default {
		... ... 
		mixins: [message],
		... ... 
}

然後可以直接通過this.toast("不能為空", 2000, false);來使用

表單

新增todo的功能,還是去coloruI的專案裡面拷貝 form的模板程式碼

<form @submit="add" @reset="clear">
	<view class="cu-form-group margin-top">
		<view class="title">新增</view>
		<input placeholder="todo" name="_name"></input>
	</view>
	<view class="padding flex flex-direction">
		<button form-type="submit" class="cu-btn bg-blue lg">儲存</button>
		<button form-type="reset" class="cu-btn bg-red margin-tb-sm lg">清空</button>
	</view>
</form>

這個新增和清空事件也非常簡單

add(e) {
	let _name = e.detail.value._name;
	if (_name === null || _name === "") {
		this.toast("不能為空", 2000, false);
		return;
	}
	const _id = this.todoList.length > 0 ? this.todoList[this.todoList.length - 1]._id + 1 : 1;
	this.todoList.push({
		_id: _id,
		_name: _name,
		_status: false
	});
	this.toast("新增成功,_id:" + _id,1000,true)
	e.detail.value = null;
},
clear() {
}

image-20201006142026519

資料快取

刪除以後我們重新整理頁面資料又回來了,可以試一下資料快取(真實開發,這些都是後端返回)

我們在switchTodo、del、add這三個事件裡面我們都新增一個快取,將最新資料快取到本地

uni.setStorageSync("todolist", this.todoList);

然後在頁面啟動的時候載入這個快取

onLoad() {
	const todolist = uni.getStorageSync("todolist")
	if (todolist != "") {
		this.todoList = uni.getStorageSync("todolist");
	} else {
		this.todoList = this.staticTodoList;
	}
},

頁面跳轉

我們新增一個todocontent頁面,方便我們點進去檢視每一個todo的詳情

然後修改一下頁面的列表渲染,增加一個點選事件

<view class="cu-item" 
:class="modalName=='move-box-'+ index?'move-cur':''" 
v-for="(todo,index) in todoList" 
:key="index"
@click="gotoContent(todo._id)"
... ... 

寫一下這個事件gotoContent,頁面傳參和網頁的形式差不多文件

gotoContent(_id) {
	uni.navigateTo({
		url: '../todocontent/todocontent?_id=' + _id
	});
},

然後在 todocontent這個頁面中接受這個引數

onLoad(e) {
	console.log(e._id);
},

冒泡點選

上面的功能實現以後會有一個問題,此時我們再次點選刪除或者切換的按鈕,就會直接跳轉到另外一個頁面了,所以我們要阻止這個點選部位的跳轉事件,很簡單

<view class="action" @click.stop="">
	<switch :checked="todo._status" @change="switchTodo" :data-_id="todo._id" />
</view>
<view class="move">
	<view class="bg-red" @click.stop="del(todo._id)">刪除</view>
</view>

網路請求

為了有意思一點,我們這個具體的content的資料將模擬後端返回

建立服務(小技巧?)

最方便的開啟一個服務可以使用vscode的 live server外掛

image-20201006144356886

我們新建個todolist.json檔案

[
    {
        "_name": "第一件事",
        "_id":1,
        "_status":false,
        "_time":1601956497000,
        "_content":"花花世界迷人眼,沒有實力別賽臉。"
    },
    {
        "_name": "第二件事",
        "_id":2,
        "_status":false,
        "_time":1601956497000,
        "_content":"天熱脾氣躁,我不微笑你別鬧。"
    },
    {
        "_name": "第三件事",
        "_id":3,
        "_status":false,
        "_time":1601956497000,
        "_content":"江南江北一條街,打聽打聽誰是爹。"
    }
]

這裡有個時間戳對吧,再介紹一個小技巧?,我們在瀏覽器中定義這樣的指令碼

image-20201006145505964

然後按ctrl + p使用快捷執行這個命令

image-20201006145543464

image-20201006145644892

想檢視更多的瀏覽器技巧嗎瀏覽器除錯

隨便建立一個html檔案然後使用live server開啟

image-20201006144427988

接著我們在位址列找到我們的json檔案,服務啟動成功!

image-20201006144454405

請求資料

我們開始在todocontent這個頁面請求資料了

首先我們要onLoad裡面進行請求

onLoad(e) {
	this.loadData(parseInt(e._id));
},

寫一下這個loadData

loadData(_id) {
	this.getTodoById(_id);
},

還用定義一個預設的空的todo物件

todo: {
	_id: -1,
	_name: "null",
	_status: false,
	_time: null,
	_content: "null"
},

寫一下這個getTodoById使用uni.request請求資料,這裡使用 promise的方式稍微寫複雜且沒有意義,單純就是為了給大家模擬一個實際開發的常規請求

async getTodoById(_id) {
	uni.showLoading();
	const value = await uni.request({
		url: 'http://127.0.0.1:5500/todolist.json'
	}).then(data => {
		uni.hideLoading();
		var [error, res] = data;
		if (error != null | res == null) {
			this.toast("網路異常", 1000, false)
			return Promise.resolve(this.todo);
		}
		if (res.data.length > 0) {
			const todo = res.data.find(todo => {
				return todo._id === _id;
			})
			return Promise.resolve(todo);
		}
	});
	this.todo = value;
}

渲染資料

還是像上面一下去拷貝一個頁面過來

<view class="flex justify-start align-center">
	<view class="text-sl">
		{{todo._name}}
	</view>
	<view class="margin-left-sm">
		{{todo._time}}
	</view>
	<view class="margin-left-sm">
		<switch :checked="todo._status" disabled="" />
	</view>
</view>
<view class="text-xl text-gray margin-top-sm">
	{{todo._content}}
</view>
<view class="padding flex flex-direction">
	<button @click="del" class="cu-btn bg-red margin-tb-sm lg">刪除</button>
</view>

image-20201006145325764

過濾器

上面的時間還是時間戳肯定是不行的,我們可以使用過濾器來轉換一下

來到main.js中,這裡的時間戳稍微寫的繁雜一點,但是很實用,可以自定義返回

//補位
function formatNumber(n) {
	n = n.toString()
	return n[1] ? n : '0' + n;
}
// 時間戳轉換日期
function formatTime(number, format) {
	if (!number || number == null) {
		return null;
	}
	let time = new Date(number);
	let newArr = []
	let formatArr = ['Y', 'M', 'D', 'h', 'm']
	newArr.push(time.getFullYear())
	newArr.push(formatNumber(time.getMonth() + 1))
	newArr.push(formatNumber(time.getDate()))
	newArr.push(formatNumber(time.getHours()))
	newArr.push(formatNumber(time.getMinutes()))
	for (let i in newArr) {
		format = format.replace(formatArr[i], newArr[i])
	}
	return format;
}
Vue.filter('strtotime', function(msg, arg) {
	return formatTime(msg, 'Y-M-D');
})

使用它

<view class="margin-left-sm">
	{{todo._time|strtotime}}
</view>

image-20201006145351729

頁面通訊

這裡有個刪除事件,可以通過 頁面通訊來通知上一個頁面刪除這個資料

定義一下這個del

del() {
	uni.$emit('del_todo', {
		_id: this.todo._id
	});
    //刪除完成後返回上一頁
	uni.navigateBack();
},

然後在上一個頁面中監聽事件

onLoad() {
	const todolist = uni.getStorageSync("todolist")
	if (todolist != "") {
		this.todoList = uni.getStorageSync("todolist");
	} else {
		this.todoList = this.staticTodoList;
	}
	uni.$on('del_todo', (data) => {
		this.del(data._id);
	})
},

下拉重新整理

如果我們想恢復最原本的資料,可以定義一個下拉重新整理事件

首先需要開啟page.json中的配置enablePullDownRefresh

"style": {
	"navigationBarTitleText": "uni-app",
	"navigationStyle": "custom",
	"usingComponents": {
		"wxcomdemo":"/wxcomponents/wxcomdemo/index"
	},
	"enablePullDownRefresh":true
}

然後在頁面中重新這個事件

onPullDownRefresh() {
	uni.setStorageSync("todolist", "")
	this.todoList=this.staticTodoList
	uni.stopPullDownRefresh();
},

完成!

條件編譯

條件編譯就是某些內容只在某個或者某些平臺編譯展示

模板中的條件編譯

比如我只想在微信小程式中展示這個內容可以使用 ifdef

<!-- #ifdef MP-WEIXIN -->
mp-weixin
<!-- #endif -->

如果是想除了微信小程式這個平臺不顯示,其他的都使用呢?使用ifndef就可以了

樣式中的條件編譯

<style lang="less">
	/*  #ifdef  MP-WEIXIN  */
	.content {
		color: #DD524D;
	}

	/*  #endif  */
</style>

未完待續!!!!

相關文章