uni-app入門教程(3)資料繫結、樣式繫結和事件處理

cutercorley發表於2020-12-15

一、模板語法及資料繫結

1.宣告和渲染變數

在使用變數前,需要先宣告,一般在data塊中進行宣告,如hello uniapp專案中index.vue中定義的title變數如下:

data() {
    return {
        title: 'Hello'
    }
},

可以在script語言塊的data塊中定義多個變數,並且在template語言塊的檢視中用{{}}呼叫變數,並且可以繫結多種型別的變數,包括基本資料型別、陣列等。

先測試基礎資料呼叫,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 class="red">
			hello-{{name}}
		</view>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				title: 'Hello',
				name: 'Corley'
			}
		},
		onLoad() {
			console.log('index onload')
		},
		onShow() {
			console.log('index onshow')
		},
		onHide() {
			console.log('index onhide')
		},
		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>

顯示:
uniapp variable define call

可以看到,定義的title和name變數渲染到了檢視中。

需要注意,宣告的變數都是響應式的,即檢視中渲染的結果與變數本身是繫結的,會同步變化,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 class="red">
			hello-{{name}}-{{age}}
		</view>
	</view>
</template>
<script>
	var _self;
	export default {
		data() {
			return {
				title: 'Hello',
				name: 'Corley',
				age: 18
			}
		},
		onLoad() {
			_self = this;
			setTimeout(function(){
				_self.age = 20
			}, 3000);
		},
		onShow() {
			console.log('index onshow')
		},
		onHide() {
			console.log('index onhide')
		},
		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>

顯示:
uniapp variable response

可以看到,在進入onLoad階段後,渲染的age變數也發生變化,變為20。

還可以對陣列進行資料繫結,可以獲取陣列的單個元素及其屬性,如下:

<template>
	<view class="content">
		<image class="logo" src="/static/logo.png"></image>
		<view class="text-area">
			<text class="title">{{title}}</text>
		</view>
		<view class="red">
			{{students[0]}}<br>
			{{students[0].name}}
		</view>
	</view>
</template>
<script>
	var _self;
	export default {
		data() {
			return {
				title: 'Hello',
				name: 'Corley',
				age: 18,
				students: [{
						name: "張三",
						age: 18
					},
					{
						name: "李四",
						age: 20
					}
				]
			}
		},
		onLoad() {
			_self = this;
			setTimeout(function() {
				_self.age = 20
			}, 3000);
		},
		onShow() {
			console.log('index onshow')
		},
		onHide() {
			console.log('index onhide')
		},
		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>

顯示:
uniapp variable array single

也可以使用迴圈來遍歷陣列,即使用v-for進行遍歷。
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 v-for="(item, index) in students">
			{{index}} - {{item.name}} : {{item.age}}
		</view>
	</view>
</template>
<script>
	var _self;
	export default {
		data() {
			return {
				title: 'Hello',
				name: 'Corley',
				age: 18,
				students: [{
						name: "張三",
						age: 18
					},
					{
						name: "李四",
						age: 20
					}
				]
			}
		},
		onLoad() {
			_self = this;
			setTimeout(function() {
				_self.age = 20
			}, 3000);
		},
		onShow() {
			console.log('index onshow')
		},
		onHide() {
			console.log('index onhide')
		},
		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>

顯示:
uniapp variable array vfor

顯然,此時遍歷出了陣列中的所有元素。

2.條件渲染

條件渲染是指滿足某個條件才渲染某個元素,使用v-if。

如下:

<template>
	<view class="content">
		<image class="logo" src="/static/logo.png"></image>
		<view class="text-area">
			<text class="title">{{title}}</text>
		</view>
		<view v-if="show1">
			show1...
		</view>
		<view v-if="show2">
			show2...
		</view>
	</view>
</template>
<script>
	var _self;
	export default {
		data() {
			return {
				title: 'Hello',
				name: 'Corley',
				age: 18,
				show1: true,
				show2: false
			}
		},
		onLoad() {
			_self = this;
			setTimeout(function() {
				_self.age = 20
			}, 3000);
		},
		onShow() {
			console.log('index onshow')
		},
		onHide() {
			console.log('index onhide')
		},
		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>

顯示:
uniapp variable array vif

此時根據v-if中傳的值判斷是否渲染。

:hidden屬性用來定義是否隱藏某個元素,如下:

<template>
	<view class="content">
		<image class="logo" src="/static/logo.png"></image>
		<view class="text-area">
			<text class="title">{{title}}</text>
		</view>
		<view :hidden="show1">
			show1...
		</view>
		<view :hidden="show2">
			show2...
		</view>
	</view>
</template>
<script>
	var _self;
	export default {
		data() {
			return {
				title: 'Hello',
				name: 'Corley',
				age: 18,
				show1: true,
				show2: false
			}
		},
		onLoad() {
			_self = this;
			setTimeout(function() {
				_self.age = 20
			}, 3000);
		},
		onShow() {
			console.log('index onshow')
		},
		onHide() {
			console.log('index onhide')
		},
		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>

顯示:
uniapp variable array hidden

可以看到,v-if:hidden的效果相反,但是原理上還是有一定區別:
v-if是根據條件決定是否渲染,:hidden會渲染但根據條件決定是否展示,可以根據具體需要進行選擇。

二、class和style繫結

前面已經提到過,可以在template語言塊的某個標籤中通過style屬性直接定義樣式,也可以在style語言塊中通過選擇器定義樣式,再在template語言塊中使用。

為節約效能,可以將Class與Style的表示式通過compiler硬編碼到uni-app中,通過條件判斷來決定是否顯示某個樣式。

1.class語法

class支援的語法方式如下:

<!-- 1 -->
<view class="static" v-bind:class="{ active: isActive, 'text-danger': hasError }">111</view>
<!-- 2 -->
<view class="static" v-bind:class="[isActive ? activeClass : '', errorClass]">222</view>
<!-- 3 -->
<view class="static" v-bind:class="[{ active: isActive }, errorClass]">333</view>
<!-- 4 -->
<view :class="{ active: isActive }">333</view>
<!-- 5 -->
<view class="static" :class="[activeClass, errorClass]">3555</view>

其中,前3種為完整形式,後2種為簡寫形式;
isActive ? activeClass : ''為三元運算子。

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 :class="{'red' : isRed}">
			class bind 2...
		</view>
		<view :class="[isBlue ? 'blue' : 'red']">
			class bind 3...
		</view>
	</view>
</template>
<script>
	export default {
		data() {
			return {
				title: 'Hello',
				name: 'Corley',
				age: 18,
				isRed: true,
				isBlue: true
			}
		},
		onLoad() {
		},
		onShow() {
			console.log('index onshow')
		},
		onHide() {
			console.log('index onhide')
		},
		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;
	}
	.blue {
		color: #007AFF;
	}
</style>

顯示:
uniapp css class

可以看到,在進行編譯選然後,微信開發者工具中wxml顯示的是被渲染後的class值。

2.style語法

style 支援的語法如下:

<!-- 1 -->
<view v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }">111</view>
<!-- 2 -->
<view v-bind:style="[{ color: activeColor, fontSize: fontSize + 'px' }]">222</view>
<!-- 3 -->
<view :style="{ color: activeColor, fontSize: fontSize + 'px' }">333</view>
<!-- 4 -->
<view :style="[{ color: activeColor, fontSize: fontSize + 'px' }]">444</view>

其中,前2種為完整形式,後2種為簡寫形式。

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 style="font-size: 10px;">
			style static...
		</view>
		<view :style="{fontSize: fontSize+'px'}">
			class dynamic...
		</view>
	</view>
</template>
<script>
	var _self;
	export default {
		data() {
			return {
				title: 'Hello',
				name: 'Corley',
				age: 18,
				fontSize: 20
			}
		},
		onLoad() {
			_self = this;
			setTimeout(function(){
				_self.fontSize = 30;
			}, 3000)
		},
		onShow() {
			console.log('index onshow')
		},
		onHide() {
			console.log('index onhide')
		},
		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;
	}
	.blue {
		color: #007AFF;
	}
</style>

顯示:
uniapp css style

顯然,樣式可以動態發生變化。

需要注意,uni-app不支援 Vue官方文件中Class 與 Style 繫結 中的 classObject 和 styleObject 語法,但是可以用 computed 方法生成 class 或者 style 字串,插入到頁面中,如下:

<template>
	<view>
		<!-- 支援 -->
		<view class="container" :class="computedClassStr"></view>
		<view class="container" :class="{active: isActive}"></view>
		<!-- 不支援 -->
		<view class="container" :class="computedClassObject"></view>
	</view>    
</template>

3.案例–動態選單切換

本案例實現動態切換導航欄。

先展示橫向排列的導航欄,index.vue如下:

<template>
	<view>
		<view v-for="(item, index) in menus" class="menu">
			{{item}}
		</view>
	</view>
</template>
<script>
	var _self;
	export default {
		data() {
			return {
				menus: [
					'新聞', '汽車', '讀書'
				]
			}
		},
		onLoad() {
			
		},
		onShow() {
			console.log('index onshow')
		},
		onHide() {
			console.log('index onhide')
		},
		methods: {

		}
	}
</script>

<style>
	.menu {
		padding: 10px;
		float: left;
		margin: 5px;
		line-height: 36px;
	}
</style>

顯示:
uniapp css case row

此時已經可以將導航欄橫向展示了。

再實現當前的導航欄顯示不一樣的顏色,如下:

<template>
	<view>
		<view v-for="(item, index) in menus" class="menu" :class="[activeIndex==index?'menuActive':'']">
			{{item}}
		</view>
	</view>
</template>
<script>
	var _self;
	export default {
		data() {
			return {
				menus: [
					'新聞', '汽車', '讀書'
				],
				activeIndex: 0
			}
		},
		onLoad() {
			
		},
		onShow() {
			console.log('index onshow')
		},
		onHide() {
			console.log('index onhide')
		},
		methods: {

		}
	}
</script>

<style>
	.menu {
		padding: 10px;
		float: left;
		margin: 5px;
		line-height: 36px;
	}
	.menuActive {
		color: #FF0000 !important;
	}
</style>

顯示:
uniapp css case row red first

此時,第1個導航欄變為紅色。

進一步實現點選時,顏色動態變化,如下:

<template>
	<view>
		<view v-for="(item, index) in menus" class="menu" :class="[activeIndex==index?'menuActive':'']" @click="menuClick" :id="index">
			{{item}}
		</view>
	</view>
</template>
<script>
	var _self;
	export default {
		data() {
			return {
				menus: [
					'新聞', '汽車', '讀書'
				],
				activeIndex: 0
			}
		},
		onLoad() {
			_self = this
		},
		onShow() {
			console.log('index onshow')
		},
		onHide() {
			console.log('index onhide')
		},
		methods: {
			menuClick: function(e){
				var aid = e.target.id;
				console.log(aid);
				_self.activeIndex = aid;
			}
		}
	}
</script>

<style>
	.menu {
		padding: 10px;
		float: left;
		margin: 5px;
		line-height: 36px;
	}
	.menuActive {
		color: #FF0000 !important;
	}
</style>

使用了事件來達到動態切換的效果。

顯示:
uniapp css case complete

可以看到,點選不同的導航欄實現了顏色同步變化的效果。

三、事件和事件繫結

1.uni-app事件

事件對映表定義了WEB事件(左側)和uni-app事件(右側)之間的對應關係,具體如下:

Web事件uni-app事件說明
click‘tap’被點選
touchstart‘touchstart’手指開始在元素上觸控時
touchmove‘touchmove’移動
touchcancel‘touchcancel’取消
touchend‘touchend’結束
tap‘tap’單機
longtap‘longtap’長按
input‘input’輸入
change‘change’改變
submit‘submit’表單提交
blur‘blur’失焦
focus: ‘focus’聚焦
reset‘reset’表單重置
confirm‘confirm’確認
columnchange‘columnchange’欄位變化
linechange‘linechange’行比那花
error‘error’錯誤
scrolltoupper‘scrolltoupper’滾動到頂部
scrolltolower‘scrolltolower’滾動到底部
scroll‘scroll’滾動

說明:
(1)在 input 和 textarea 中 change 事件會被轉為 blur 事件;
(2)列表中沒有的原生事件也可以使用,例如map元件的regionchange 事件直接在元件上新增@regionchange修飾即可,同時這個事件也非常特殊,它的 event type 有 begin 和 end 兩個,導致我們無法在handleProxy 中區分到底是什麼事件,所以在監聽此類事件的時候同時監聽事件名和事件型別,即<map @regionchange="functionName" @end="functionName" @begin="functionName"><map>
(3)由於平臺的差異,bind 和 catch 事件同時繫結時,只會觸發 bind,catch 不會被觸發,使用時需要注意。

  • 事件修飾符:
    使用stop會阻止冒泡,但是同時繫結了一個非冒泡事件,會導致該元素上的 catchEventName 失效;
    prevent 可以直接結束事件,因為uni-app裡沒有什麼預設事件,比如 submit 並不會跳轉頁面;
    self 沒有可以判斷的標識;
    once 也不能做,因為uni-app沒有 removeEventListener, 雖然可以直接在 handleProxy 中處理,但是並不優雅;
  • 按鍵修飾符:
    uni-app執行在手機端,沒有鍵盤事件,所以不支援按鍵修飾符。

2.事件繫結

使用@對元素進行事件繫結,當事件被觸發時,會導致相應的操作。

index.vue如下:

<template>
	<view>
		<view class="demo" @click="clickTest" @longtap="longtap"></view>
	</view>
</template>
<script>
	var _self;
	export default {
		data() {
			return {
			}
		},
		onLoad() {
			_self = this
		},
		onShow() {
			console.log('index onshow')
		},
		onHide() {
			console.log('index onhide')
		},
		methods: {
			clickTest : function(e){
				console.log("click")
			},
			longtap : function(e){
				console.log("longtap")
			},
		}
	}
</script>

<style>
	.demo {
		width: 600rpx;
		height: 600rpx;
		background: #DD524D;
	}
</style>

顯示:
uniapp event bind

可以看到,在進行點選和長按時,會觸發不同的事件、執行不同的操作。

注意在小程式中觀察對應事件物件,可以利用此物件獲取更多資訊。

3.事件傳參

在觸發事件時,還可以傳入動態引數。

如下:

<template>
	<view>
		<view v-for="(item, index) in students" class="persons" @click="menuClick" v-bind:id="index">{{index}} - {{item.name}}</view>
	</view>
</template>
<script>
	var _self;
	export default {
		data() {
			return {
				students: [{
						name: "張三",
						age: 18
					},
					{
						name: "李四",
						age: 20
					}
				]
			}
		},
		onLoad() {
			_self = this
		},
		onShow() {
			console.log('index onshow')
		},
		onHide() {
			console.log('index onhide')
		},
		methods: {
			menuClick: function(e) {
				console.log(e);
				console.log(e.target.id);
			},
		}
	}
</script>

<style>
	.demo {
		width: 600rpx;
		height: 600rpx;
		background: #DD524D;
	}
</style>

顯示:
uniapp event bind param

可以看到,在進行點選時,控制檯列印出了事件物件和e.target.id的值。

再如:

<template>
	<view>
		<view class="demo" id="outid" @click="clickTest" @longtap="longtap">
			<view id="inid" style="width: 400rpx;height: 400rpx;background: #007AFF;"></view>
		</view>
	</view>
</template>
<script>
	var _self;
	export default {
		data() {
			return {
			}
		},
		onLoad() {
			_self = this
		},
		onShow() {
			console.log('index onshow')
		},
		onHide() {
			console.log('index onhide')
		},
		methods: {
			clickTest : function(e){
				console.log(e.currentTarget.id)
				console.log(e.target.id)
			},
			longtap : function(e){
				console.log("longtap")
			},
		}
	}
</script>

<style>
	.demo {
		width: 600rpx;
		height: 600rpx;
		background: #DD524D;
	}
</style>

顯示:
uniapp event bind current

可以看到,在點選外部紅色區域時,列印的兩個id值相同;
而在點選內部藍色區域時,e.target變為內部的view元素,所以列印出的也是inid,所以在使用屬性傳參時儘量使用e.currentTarget

相關文章