uni-app组件与生命周期

uni-app组件

在实际制作页面的过程中,我们不会在一个页面中布局所有参数,而是将页面分为多个部分,每个部分都是一个组件。最后在页面中调用这些组件,形成页面。

创建组件

步骤:1. 选中项目-右键-新建-2.目录,创建一个名为components的目录。
在这里插入图片描述
2. 选中components-右键-新建组件。
在这里插入图片描述
3. 输入组件的名称,记得要选中左下角的创建同名目录。组件名称有两种命名方式:一种是驼峰的形式,如:UserInfo;一种是官方形式,如:uni-icon。
在这里插入图片描述

调用组件

按照刚刚说的命名方式,创建组件UserInfo,定义文字与图片,然后创建页面demo,在demo中调用组件,代码这样写:

<template>
	<view class="">
		<UserInfo></UserInfo>
	</view>
</template>

<script setup>
	
</script>

<style lang="scss" scoped>
	       
</style>

成功调用组件了:
在这里插入图片描述

使用props在组件中进行数据传递

多个页面有时会共用一个组件,但会对组件部分内容进行修改,这时就要用到props进行数据传递,修改组件。
重新定义组件UserInfo,然后在页面中写入三个UserInfo,这时页面会出现三个一样的布局:
在这里插入图片描述
现在尝试去修改,创建新页面demo作为页面,UserInfo是组件。要向组件中传值,首先要确保UserInfo可以接收到页面传来的命令,先在UserInfo声明defineProps,代码格式如下:

<template>
	<view class="userinfo">
		<image :src="avatar" mode="" class="avatar"></image>
		<view class="username">{{username}}</view>
	</view>
</template>

<script setup>
defineProps(['username','avatar'])	
</script>

<style lang="scss" scoped>
.userinfo{
	width: 100%;
	height: 200px;
	background: #ccc;
	display: flex;
	align-items: center;
	justify-content: center;
	flex-direction: column;
	image{
		width: 100px;
		height: 100px;
		border-radius: 50%;
	}
	.username{
		padding: 10px 0 ;
		font-size: 20px;
		
	}
}
</style>

然后就可以在父组件页面中去设置了,代码格式如下:

<template>
	<view class="">
		<UserInfo username = "老三" avatar = "../../static/pic1.jpg"></UserInfo>
		<UserInfo username = "王五" avatar = "../../static/pic2.jpg"></UserInfo>
		<UserInfo username = "李四" avatar = "../../static/pic3.jpg"></UserInfo>
	</view>
</template>

<script setup>
	
</script>

<style lang="scss" scoped>
	       
</style>


页面把值传递给了组件,这是最终的效果,可以看到相同的组件拥有不同的文字和图片:
在这里插入图片描述
要是想在组件中对页面传过来的值进行修改,还得用到computed计算属性,且define要定义成常量。比如这里我们要在文字后面加上一个“@”,要这样写:

<template>
	<view class="userinfo">
		<image :src="avatar" mode="" class="avatar"></image>
		<view class="username">{{myname}}</view>
	</view>
</template>

<script setup>
import {computed} from "vue"
const prop = defineProps(['username','avatar'])	
const myname = computed(()=>prop.username + "@")
</script>

<style lang="scss" scoped>
.userinfo{
	width: 100%;
	height: 200px;
	background: #ccc;
	display: flex;
	align-items: center;
	justify-content: center;
	flex-direction: column;
	image{
		width: 100px;
		height: 100px;
		border-radius: 50%;
	}
	.username{
		padding: 10px 0 ;
		font-size: 20px;
		
	}
}
</style>

效果:
在这里插入图片描述

prop校验与prop默认值用法及循环遍历数组对象

刚刚我们在页面中写入了三个UserInfo,并为其定义了username名称,现在删除第二个UserInfo中的username,名称一栏就会空出了,如下图。我们可以设置一个默认值,这样没有定义名称时就会有默认名称显示了。
在这里插入图片描述
用另一种方式定义defineProps,就可以设置默认值了,如代码所示:

<template>
	<view class="userinfo">
		<image :src="avatar" mode="" class="avatar"></image>
		<view class="username">{{username}}</view>
	</view>
</template>

<script setup>
const prop = defineProps({
	username:{
		type:String,
		default:"匿名"
	}, 
	avatar:{
		type:String,
		default:"../../static/logo.png"
	}
})	
</script>

<style lang="scss" scoped>
.userinfo{
	width: 100%;
	height: 200px;
	background: #ccc;
	display: flex;
	align-items: center;
	justify-content: center;
	flex-direction: column;
	image{
		width: 100px;
		height: 100px;
		border-radius: 50%;
	}
	.username{
		padding: 10px 0 ;
		font-size: 20px;
		
	}
}
</style>

刚刚我们给图片也设置了默认值,那就把第二个UserInfo中的图片也删除,看看设置默认值后的效果:
在这里插入图片描述
刚刚我们设置的名称和图片,放到对象中去会显得更加简洁。接下来,尝试传递对象给组件:首先,要在组件中设置defineProps接受obj,并在template中渲染,然后在页面中script区域定义对象,并在template中调用。要注意的是,在给对象设置默认值时,要写函数的形式,return一下。
页面代码:

<template>
   <view class="">

   <UserInfo v-for="(item,index) in userinto" :obj = "item"></UserInfo>
   </view>
</template>

<script setup>
import {ref} from "vue" ;
const userinto = ref([
   {name:"王二麻子",avatar:"../../static/pic1.jpg"},
   {name:"王五子",avatar:"../../static/pic2.jpg"},
   {name:"张三子",avatar:"../../static/pic3.jpg"},
]

)

</script>

<style lang="scss" scoped>
          
</style>


子组件代码:

<template>
	<view class="userinfo">
		<image :src="obj.avatar" mode="" class="avatar"></image>
		<view class="username">{{obj.name}}</view>
	</view>
</template>

<script setup>

defineProps({
	obj:{
		type:Object,
		default(){
			return{name:"匿名",avatar:"../../static/logo.png"}
		}
	}
})
 </script>

<style lang="scss" scoped>
.userinfo{
	width: 100%;
	height: 200px;
	background: #ccc;
	display: flex;
	align-items: center;
	justify-content: center;
	flex-direction: column;
	image{
		width: 100px;
		height: 100px;
		border-radius: 50%;
	}
	.username{
		padding: 10px 0 ;
		font-size: 20px;
		
	}
}
</style>

插槽slots及具名插槽实现组件高度定制化

插槽可以让我们定制一个更加强大的组件,新建组件,同时,创建两个页面demo1和demo2,组件分为三个区域,代码如下:

<template>
	<view class="layout">
		<view class="header">
			header区域
		</view>
		<view class="main">
		中心内容区
		</view>
		<view class="footer">底部区域</view>
	</view>
</template>

<script setup>
	
</script>

<style lang="scss">
.layout{
	.header{
		height: 100px;
		background: #cfcfcf;
	}
	.footer{
		height: 120px;
		background: orange;
	}
}
</style>

在demo1和demo2中调用这个组件,此时,demo1和demo2的页面是一摸一样的。尝试分别定义这两个页面,组件中有三个区域header、main、footer,我们要定义中间的main,就在main内放入一个标签,然后就可以去demo1和demo2的组件标签中定义,下面是demo1的代码,在组件标签内填写任意内容;在demo2相应区域填写其他内容,这样就实现了两个页面共用一个组件,但实现了个性化定制。

<template>
	<view class="">
		<Pin-layout>
		个性化定制内容
		</Pin-layout>
	</view>
</template>

<script setup>
	
</script>

<style lang="scss" scoped>
	       
</style>

若是还想定制header和footer的界面,就不能只在组件中写上slot标签了,要使用具名插槽为slot定义名称,就像这样:

<template>
	<view class="layout">
		<view class="header">
			<slot name="header"></slot>
		</view>
		<view class="main">
			<slot name="main"></slot>
		</view>
		<view class="footer">
			<slot name="footer"></slot>
		</view>
	</view>
</template>

<script setup>
	
</script>

<style lang="scss">

</style>

页面中,用template标签,使用v-slot属性,它还有一个简写,就是用#代替它,demo1示例代码如下:

<template>
	<view class="">
		<Pin-layout>
			<template v-slot:header>
				首页头部
			</template>
			<template #main>
				首页的内容
			</template>
		</Pin-layout>
	</view>
</template>

<script setup>
	
</script>

<style lang="scss" scoped>
	       
</style>

组件中emit的声明触发事件

前面都是页面向组件传值,页面传递给组件的是单向数据流,组件是没法对值进行修改的。现在试着从组件返回值给页面。

在组件中,定义@click= “$emit(‘add’,123)” 括号前面是数据名称,后面是数据的值,这里我们设置随机数:

<template>
	<view>
		子组件
		<button @click="$emit('add',Math.random())">按钮</button>
	</view>
</template>

<script setup>


</script>

<style lang="scss" scoped>

</style>

在页面中,定义@add="onAdd",等于是接受add,然后在script中新建常量。

<template>
	<view class="">
		<Pin-child @add= "onAdd"></Pin-child>
	</view>
</template>

<script setup>
	const onAdd = function(e){
		console.log(e);
	}


</script>

<style lang="scss" scoped>

</style>

页面成功接收到了组件的返回值:

在这里插入图片描述

这种方式用的比较少,用的更多的是在组件的script代码中定义。用常量定义defineEmits要返回的数据名称,然后,新建函数,定义数据名称与数据的值,最后在template中调用该函数,例如:

<template>
	<view>
		子组件
		<button @click="onClick">按钮</button>
	</view>
</template>

<script setup>
	const emit = defineEmits(["add"])
	function onClick(){
		emit("add",Math.random())
	}
</script>

<style lang="scss" scoped>


</style>

vue3组合式API中的组件的生命周期函数(钩子函数)

生命周期函数主要用于在特定时间点执行特定的操作。 这就像一个人从出生到死亡会经历不同的阶段一样,Vue组件也会经历从创建到销毁的一系列过程,这些过程中的特定时间点就是生命周期函数的执行时机。
在uni-app中,分为Vue3的组件生命周期和uni-app自带的页面生命周期,一般来说,页面生命周期已经足够我们使用了。关于生命周期,可以看一下这篇文章: uniappVue3版本中组件生命周期和页面生命周期的详细介绍

onMoundted

在以下页面代码中,我们首先在scroll-view中创建了ref="scroll"引用,指向滚动视图组件的实例。通过这个引用,你可以在Vue组件的其他部分访问和操作这个滚动视图。在script中,是拿不到template中的引用的,因为此时DOM还属于虚拟DOM,使用onMounted让虚拟DOM变成真实DOM,就可以拿到了,如:

<template>
	<view class="layout">
		<scroll-view scroll-y="true" ref="scroll">
			<view></view>
		</scroll-view>
	</view>
</template>

<script setup>
import {onMounted, ref} from "vue" ;
const scroll = ref(null) ;

onMounted(()=>{
	console.log(scroll.value);
})		
</script>

<style lang="scss" scoped>
	       
</style>

在这里插入图片描述

onUnmounted

一般是在组件中完成监听,用于在组件卸载时执行一些清理操作,演示一下,先在life-demo组件中定义onUnmounted,代码如下:

<template>
	<view>
		子组件
	</view>
</template>

<script setup>
	import {onUnmounted} from "vue"
	onUnmounted(()=>{
		console.log("子组件被卸载了");
	})
</script>

<style lang="scss">

</style>

然后在页面中,调用组件,并为其设置v-if,默认它是true的,设置定时2秒后,关闭组件,然后观察组件中是否能监听到,代码如下:

<template>
	<view class="layout">
		<life-demo v-if="show"></life-demo>
	</view>
</template>

<script setup>
import {onMounted, ref} from "vue" ;
const scroll = ref("") ;
const show = ref(true);
setTimeout(()=>{
	show.value = false
},2000)

	
</script>

<style lang="scss" scoped>
	       
</style>

2秒钟后,组件关闭了,打印了返回值。
在这里插入图片描述

使用defineExpose暴露子组件的属性及方法

前面在组件中使用了emit向页面传值,还可以在页面直接从组件中取值,那就是使用defineExpose属性。在正常情况下,script中的常量只能用于本页面,要是在其他页面中使用,就要用到defineExpose属性,设置格式是”属性: 值“,接下来,演示一下如何使用,我们在组件中使用这个属性,代码如下:

<template>
	<view class="out">
		子组件
	</view>
</template>

<script setup>
	import {ref} from "vue"
	const count = ref(100)
	
	defineExpose({
		count,
		str:"Pin"
	})
</script>

<style lang="scss" scoped>

</style>

然后在页面template区域里定义ref,通过onMounted函数,就可以拿到组件中的值了,页面代码如下:

<template>
	<view class="layout">
		<demo-child ref="child"> </demo-child>
	</view>
</template>

<script setup>
	import {onMounted, ref} from "vue"
	const child = ref(null);
	onMounted(()=>{
		console.log(child.value)
	})
</script>

<style lang="scss" scoped>
	       
</style>

已取到值:
在这里插入图片描述
函数也可以从组件中取到,现在组件中定义函数updateCount,并将其暴露:

<template>
	<view class="out">
		子组件count的值:{{count}}
	</view>
</template>

<script setup>
	import {ref} from "vue"
	const count = ref(100)
	const updateCount = function(){
		count.value++
	}
	defineExpose({
		count,
		str:"Pin",
		updateCount
	})
</script>

<style lang="scss" scoped>

</style>

在页面中,调用组件的函数:

<template>
	<view class="layout">
		<demo-child ref="child"> </demo-child>
		<view>-----</view>
		<button @click="update">点击修改count的值</button>
	</view>
</template>

<script setup>
	import {onMounted, ref} from "vue"
	const child = ref(null);
	const update = function(){
		child.value.updateCount()
	}
	onMounted(()=>{
		console.log(child.value)
	})
	
</script>

<style lang="scss" scoped>
	.out{
		padding: 20px;
		background: #eee;
	}       
</style>

成功调用,不仅取到了子组件的值,还对其进行了修改。
在这里插入图片描述

页面生命周期onLoad和onReady在vue3组合式API中的使用

onLoad

使用onLoad要从@dcloudio/uni-app中导入方法,格式如下:

import {onLoad} from "@dcloudio/uni-app"

在onLoad中有个回调函数,即跳转后可以接收到上个页面传来的参数,我们把刚刚的demo5页面拿过来,设置跳转页面并传参到新的页面demo6,代码如下:

<template>
	<view class="layout">
		<demo-child ref="child"> </demo-child>
		<view>-----</view>
		<button @click="update">点击修改count的值</button>
		<navigator url="/pages/demo6/demo6?name=王五&age=20">跳转到demo6</navigator>
	</view>
</template>

<script setup>
	import {onMounted, ref} from "vue"
	const child = ref(null);
	const update = function(){
		child.value.updateCount()
	}
	onMounted(()=>{
		console.log(child.value)
	})
	
</script>

<style lang="scss" scoped>
	.out{
		padding: 20px;
		background: #eee;
	}       
</style>

进入到浏览器点击跳转,可以看到跳转后的链接里显示着参数:
在这里插入图片描述
那我们现在要接受这个参数,就要用到新页面demo6中的onLoad函数,然后把拿到的值赋给name,代码是这样的:

<template>
	<view class="content">
		<view>
		姓名:{{name}}
		</view>
	</view>
</template>

<script setup>
	import{ref} from "vue"
	import{onLoad} from "@dcloudio/uni-app"
	const name = ref("张三")
	onLoad((e)=>{
		name.value = e.name
	})
	
</script>

<style scoped>
	
</style>

一般我们要接受参数的话,才会用到onLoad。

onReady

与组件onMounted类似,都是DOM体挂载完毕了,然后我们就可以操作template上的节点了。在demo6的template中写入scroll的ref值,通过onLoad是无法拿到的,用onReady就可以拿到,代码如下:

<template>
	<view class="content">
		<view>
		姓名:{{name}}
		<scroll-view scroll-y="true" ref="scroll">
			<view></view>
		</scroll-view>
		</view>
	</view>
</template>

<script setup>
	import{ref} from "vue"
	import{onLoad,onReady} from "@dcloudio/uni-app"
	const name = ref("张三")
	const scroll = ref(null)
	onLoad((e)=>{
		name.value = e.name
	})
	onReady(()=>{
		console.log(scroll.value)
	})
	
</script>

<style scoped>
	
</style>

但若是回调函数的话,只有用onLoad才可以,onReady是没有这个功能的。

onShow和onHide钩子的对比和执行顺序

onShow和onHide、onLoad有什么区别:onLoad是进入页面时就会触发,onHide是离开页面时触发,onShow是回到页面时触发,刚刚我们写了代码是从demo5跳转到demo6,现在我们写个代码让它能从demo6再跳回demo5,这下他俩之间就可以互跳了。现在,在demo6中定义一个计时器,然后根据onShow和onHide的属性,实现离开页面停止计时,回到页面开始计时的功能,这是demo6的代码:

<template>
	<view class="content">
		<view>
		姓名:{{name}}
		<scroll-view scroll-y="true" ref="scroll">
			<view></view>
		</scroll-view>
		<navigator url="/pages/demo5/demo5">跳转到demo5</navigator>
		</view>
		<view>----</view>
		<view>计数:{{count}}</view>
	</view>
</template>

<script setup>
	import{ref} from "vue"
	import{onLoad,onReady,onShow, onHide} from "@dcloudio/uni-app"
	const name = ref("张三")
	const scroll = ref(null)
	const count = ref(0)
	
let time =	setInterval(()=>{
		count.value++
	},50)
	
	 onLoad(()=>{
	 	console.log("onLoad函数")
	 })
	 onShow(()=>{
	 	console.log("onShow函数")
	 })
	 onReady(()=>{
	 	console.log("onReady函数")
	 })
	 onHide(()=>{
		 console.log("onHide函数")
	 })
</script>

<style scoped>
	
</style>

计时器现在是一直在计时的,即使在后台也是在计时:
在这里插入图片描述
现在,在onHide中设置 clearInterval,也就是离开页面时停止计时;然后在onShow设置开始计时,也就是回到页面开始计时,代码如下:

<template>
	<view class="content">
		<view>
		姓名:{{name}}
		<scroll-view scroll-y="true" ref="scroll">
			<view></view>
		</scroll-view>
		<navigator url="/pages/demo5/demo5">跳转到demo5</navigator>
		</view>
		<view>----</view>
		<view>计数:{{count}}</view>
	</view>
</template>

<script setup>
	import{ref} from "vue"
	import{onLoad,onReady,onShow, onHide} from "@dcloudio/uni-app"
	const name = ref("张三")
	const scroll = ref(null)
	const count = ref(0)
	
let time =	setInterval(()=>{
		count.value++
	},50)
	
	 onLoad(()=>{
	 	console.log("onLoad函数")
	 })
	 onShow(()=>{
	 	console.log("onShow函数")
		time =	setInterval(()=>{
				count.value++
			},50)
	 })
	 onReady(()=>{
	 	console.log("onReady函数")
	 })
	 onHide(()=>{
		 console.log("onHide函数")
		 clearInterval(time)
	 })
</script>

<style scoped>
	
</style>

功能成功实现,离开页面停止计时,回到页面又开始计时了:
在这里插入图片描述

onUnload页面卸载和onPageScroll监听页面滚动

onUnload

onUnload只有在打开新页面同时关闭所有页面时才会触发,所以在设置navigator时,我们要用reLaunch属性,同时,定义一个onUnload,代码如下:

<template>
	<view class="content">
		<view>
		姓名:{{name}}
		<scroll-view scroll-y="true" ref="scroll">
			<view></view>
		</scroll-view>
		<navigator url="/pages/demo5/demo5">跳转到demo5</navigator>
		</view>
		<view>----</view>
		<view>计数:{{count}}</view>
		<view>----</view>
		<navigator open-type = "reLaunch" url= "/pages/demo4/demo4">跳转到demo4</navigator>
	</view>
</template>

<script setup>
	import{ref} from "vue"
	import{onLoad,onReady,onShow, onHide,onUnload} from "@dcloudio/uni-app"
	const name = ref("张三")
	const scroll = ref(null)
	const count = ref(0)
	
let time =	setInterval(()=>{
		count.value++
	},50)
	
	 onLoad(()=>{
	 	console.log("onLoad函数")
	 })
	 onShow(()=>{
	 	console.log("onShow函数")
		time =	setInterval(()=>{
				count.value++
			},50)
	 })
	 onReady(()=>{
	 	console.log("onReady函数")
	 })
	 onHide(()=>{
		 console.log("onHide函数")
		 clearInterval(time)
	 })
	 onUnload(()=>{
		 console.log("页面被卸载")
	 })
</script>

<style scoped>
	
</style>

跳转到demo4时,onUnload被触发了,在实际应用中,onUnload一般会用于一些缓存的清除
在这里插入图片描述

onPageScroll

onPageScroll是用于监听滚动页面的,下面我们就利用onPageScroll来实现这个功能,让滚动条拖动到底部时显示箭头,向上滚动时箭头消失。先用v-for循环一组数,让页面产生滚动条。然后我们定义一个向上的箭头,并为其设置样式,后设置一个fixed变量定义为false,再给onPageScroll设置判断逻辑,让箭头在一定的条件下出现,代码如下:

<template>
	<view class="content">
		<view>
		姓名:{{name}}
		<scroll-view scroll-y="true" ref="scroll">
			<view></view>
		</scroll-view>
		<navigator url="/pages/demo5/demo5">跳转到demo5</navigator>
		</view>
		<view>----</view>
		<view>计数:{{count}}</view>
		<view>----</view>
		<navigator open-type = "reLaunch" url= "/pages/demo4/demo4">跳转到demo4</navigator>
		<view v-for="item in 50">{{item}}</view>
		<view class="fixed" v-if="fixed">⬆</view>
	</view>
</template>

<script setup>
	import{ref} from "vue"
	import{onLoad,onReady,onShow, onHide,onUnload,onPageScroll} from "@dcloudio/uni-app"
	const name = ref("张三")
	const scroll = ref(null)
	const count = ref(0)
	const fixed = ref(false)
	
let time =	setInterval(()=>{
		count.value++
	},50)
	
	 onLoad(()=>{
	 	console.log("onLoad函数")
	 })
	 onShow(()=>{
	 	console.log("onShow函数")
		time =	setInterval(()=>{
				count.value++
			},50)
	 })
	 onReady(()=>{
	 	console.log("onReady函数")
	 })
	 onHide(()=>{
		 console.log("onHide函数")
		 clearInterval(time)
	 })
	 onUnload(()=>{
		 console.log("页面被卸载")
	 })
	 onPageScroll((e)=>{
		 fixed.value = e.scrollTop>200
		 // if(e.scrollTop>200){
			//  fixed.value = true
		 // }else{
			//  fixed.value = false
		 // }
	 })
</script>

<style scoped>
.fixed{
	width: 100px;
	height: 100px;
	background: orange;
	position: fixed;
	right: 30px;
	bottom: 30px;
}	
</style>

成功实现:
在这里插入图片描述

相关推荐

  1. Uni-App 生命周期

    2024-07-22 11:54:03       28 阅读
  2. React 生命周期

    2024-07-22 11:54:03       37 阅读
  3. uni-app生命周期(应用,页面生命周期

    2024-07-22 11:54:03       26 阅读
  4. Vue生命周期

    2024-07-22 11:54:03       49 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-22 11:54:03       52 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-22 11:54:03       54 阅读
  3. 在Django里面运行非项目文件

    2024-07-22 11:54:03       45 阅读
  4. Python语言-面向对象

    2024-07-22 11:54:03       55 阅读

热门阅读

  1. Linux 驱动学习笔记

    2024-07-22 11:54:03       14 阅读
  2. 掌握Git:面试中常见的问题与解答

    2024-07-22 11:54:03       16 阅读
  3. DOS常用命令大全

    2024-07-22 11:54:03       12 阅读
  4. 设计模式在FileBrowser中的几个应用

    2024-07-22 11:54:03       13 阅读
  5. 代码随想录 day 17 二叉树

    2024-07-22 11:54:03       16 阅读
  6. Golang_交替打印ABC\奇偶数\1-10\字母(并发编程)

    2024-07-22 11:54:03       15 阅读
  7. 每天一个数据分析题(四百三十六)- 正态分布

    2024-07-22 11:54:03       16 阅读
  8. 使用Event Sourcing模式管理应用状态

    2024-07-22 11:54:03       18 阅读
  9. 从0到1搭建数据中台(4):TiDB的安装和使用

    2024-07-22 11:54:03       16 阅读
  10. Modbus协议了解与简单使用

    2024-07-22 11:54:03       20 阅读
  11. springboot引入kafka

    2024-07-22 11:54:03       14 阅读