uniapp前端开发基础知识 - vue基础 | 青训营笔记

151 阅读7分钟

uniapp前端开发基础知识 | 青训营笔记

这是我参与「第五届青训营 」伴学笔记创作活动的第 6 天

虽然我是后端基础班的同学,但是我还是学习了一部分前端的知识,希望能够将抖音项目的前后端完整地设计出来。

开发工具

HBuilder-X

uni-app程序开发

这是一个测试项目,仅仅用于学习vue和uniapp开发的基础知识

前置知识学习

  • 前端三件套
  • Vue框架
  • 一门后端语言(这里采用node.js进行,后期会重构成golang语言)

前端知识学习

生命周期

  • 应用生命周期
    • 应用生命周期:可以通过App.vue当中的某些函数进行监视
      • 通过下面的函数可以做到对应用进行一定的监听,例如其中的函数onLaunch是程序开始运行,onHide是后台运行,onShow是正在运行(前台),onLoad是页面正在加载
<script>
	export default {
		onLaunch: function() {
			console.log('App Launch')
		},
		onShow: function() {
			console.log('App Show')
		},
		onHide: function() {
			console.log('App Hide')
		}
	}
</script>
  • 页面生命周期
    • 通过我们对某一个页面监听的时候,页面第一次打开的时候会调用onLoad,如果切换到其他页面会调用onHide,隐藏之后打开只会调用onShow,而不会调用onLoad

在uni-app当中使用vue

创建变量

对于下面一个模板,我们需要创建一个变量,那么就在data当中写入,然后可以利用{{}}来书写模板语法,这里类似于python-flask当中的jinja2语法,利用双大括号来进行

<template>
	<view>
		{{test}}
	</view>
</template>

<script>
	export default {
		// 这里用于存放变量,然后在上面使用模板语法
		data() {
			return {
				test:'hello world'
			}
		},
		onLoad() {
			console.log("Loading")
		},
		onShow(){
			console.log("Show")
		},
		onHide(){
			console.log("Hide")
		},
		methods: {
			
		}
	}
</script>

<style>

</style>

同时比较优秀的一点是,如果我们修改data,页面也会重新渲染,也就是同步的发生了修改

下面还有一种做法,可以利用指令"v-text"进行绑定

<template>
	<view v-text="test" class="content">
	</view>
</template>

利用上面的指令就也可以让我们其中填入text变量的值

同样的我们也可以使用v-html="xxxx"的样子,这个与v-text的不同在于,v-html会进行html解析和渲染,而利用v-text仅仅会将我们填入的数据当作字符串来展现

这里需要注意的是v-text的使用等效于{{}}的模板语法

样式绑定

*一般方式

  • 我们可以利用简单的css选择器,选择在html当中的标签,利用class和id等,然后在页面当中的style当中编写
  • 对于一些全局的样式,我们可以在App.vue当中进行编写

当然上面的方式都是利用原本三件套的编写方式

*利用vue的方式

  • 我们可以先创建一个变量在data里面,然后利用 v-bind:style = "style" 就可以进行操作了
<template>
	<view v-text="test" class="content" v-bind:style="style">
	</view>
</template>

<script>
	export default {
		// 这里用于存放变量,然后在上面使用模板语法
		data() {
			return {
				test:'hello world',
				style:'font-size:30px; color:red;'
			}
		},
		onLoad() {
			console.log("Loading")
		},
		onShow(){
			console.log("Show")
		},
		onHide(){
			console.log("Hide")
		},
		methods: {
			
		}
	}
</script>

<style>

</style>

利用上面的方式就可以进行绑定

当然也有简略的语法,类似于下面的

<template>
	<view :class="test" v-bind:style="style">
		hello world
	</view>
</template>

<script>
	export default {
		// 这里用于存放变量,然后在上面使用模板语法
		data() {
			return {
				test:'text',
				style:'font-size:30px; color:red;'
			}
		},
		onLoad() {
			console.log("Loading")
		},
		onShow(){
			console.log("Show")
		},
		onHide(){
			console.log("Hide")
		},
		methods: {
			
		}
	}
</script>

<style>

</style>

直接:就可以进行变量的绑定了,同时是动态变化的,如果变量发生改变,会重新发生渲染,这样我们就可以实现一个动态的效果

事件绑定

练习:点击hello world的时候,让我们的字体发生颜色的改变 下面的函数利用v-on:click绑定了函数click,这样我们点击的时候就会调用click函数,然后实现颜色的切换

<template>
	<!-- 我们这里绑定了click事件,我们应该在methods当中定义这个函数 -->
	<view :class="test" v-bind:style="style" v-on:click="click">
		hello world
	</view>
</template>

<script>
	export default {
		// 这里用于存放变量,然后在上面使用模板语法
		data() {
			return {
				test:'text',
				style:'font-size:30px; color:red;'
			}
		},
		onLoad() {
			console.log("Loading")
		},
		onShow(){
			console.log("Show")
		},
		onHide(){
			console.log("Hide")
		},
		methods: {
			click:function(){
				this.style="font-size:30px; color:black;"
			}
		}
	}
</script>

<style>

</style>

当我们点击的时候就可以很好的完成这样的效果,我们的v-on:click可以简写成为@click就完成了

条件渲染

练习:利用按钮,让我们显示的文本隐藏,再次点击让文本重新显示

下面的代码利用了v-if进行了条件渲染,当v-if当中绑定的表达式为true的时候,那就会显示,否则就不会显示,这样我们点击的时候就可以完成我们可以利用多种方式实现click的逻辑,例如使用if判断,使用三目运算符,都可以简单的进行。

<template>
	<view>
		<!-- 当v-if当中的值为true的时候,下面的文本会显示,否则不会显示 那么这样我们可以绑定一个变量,然后通过button来改变这个变量-->
		<view :class="test" v-bind:style="style" v-if="show">
			hello world
		</view>
		<button @click="click">
			按钮
		</button>
	</view>
</template>

<script>
import { vShow } from "vue"
	export default {
		// 这里用于存放变量,然后在上面使用模板语法
		data() {
			return {
				test:'text',
				style:'font-size:30px; color:red;',
				show:true
			}
		},
		onLoad() {
			console.log("Loading")
		},
		onShow(){
			console.log("Show")
		},
		onHide(){
			console.log("Hide")
		},
		methods: {
			click:function(){
				this.show = !this.show
			},
		}
	}
</script>

<style>

</style>

这里有另外一个元素是v-show,两者的区别在于v-show并不会删除原本的元素,而使用v-if会删除原本的元素,再点击的时候会重新渲染。

看下面的代码

		<view :class="test" v-bind:style="style" v-if="show">
			hello world
		</view>
		<view v-else>good bye world</view>

这里有一个新的标签是v-else,这里实现了两者的渲染,v-if必须是和其相邻的标签

列表渲染

练习:当我们需要使用大量相同的标签的时候,例如我们打印10个hello world

代码都相同,如果我们重复写的话,就会有很多的冗余,所以我们可以使用v-for列表渲染

<template>
	<view class="content">
		<view class="" v-for="item in list">
			hello world
			{{item}}
		</view>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				list:[1,2,3,4,5,6,7,8,9,10]
			}
		},
		onLoad() {

		},
		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>

这样的话我们就可以完成了

当然也可以看下面一段代码

<template>
	<view class="content">
		<view class="" v-for="(item, index) in list" :key="index">
			hello world
			{{item}} ----- {{index}}
		</view>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				list:[1,2,3,4,5,6,7,8,9,10]
			}
		},
		onLoad() {

		},
		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>

v-model的使用

题目:我们需要读取input当中的文本,并存储为一个变量

我们通过v-model实现了双向绑定

看下面的代码实现:

<template>
	<view class="content">
		<!-- 我们可以将其中的内容存储到一个变量当中 -->
		<input type="text" value="" v-model="text"/>
		<button type="primary" @click="click">按钮</button>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				text : ''
			}
		},
		onLoad() {

		},
		methods: {
			click(){
				console.log(this.text)
			}
		}
	}
</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>

也就是我们修改text的时候,里面的内容会发生改变,如果改变input当中的内容,text的变量值也会发生改变

这样我们在这里可以实现一个更加复杂的逻辑,我们每次点击提交,让上面input的内容加入到下面,同时清空input里面的内容

<template>
	<view class="content">
		<!-- 我们可以将其中的内容存储到一个变量当中 -->
		<input type="text" value="" v-model="text"/>
		<button type="primary" @click="click">按钮</button>
		<view>
			<view class="" v-for="item in list">
				{{item}}
			</view>
		</view>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				text : '',
				list : ["hello", "world"]
			}
		},
		onLoad() {

		},
		methods: {
			click(){
				this.list.push(this.text)
			}
		}
	}
</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>

上面的实现利用了以下的思路:

  • 利用v-model和变量的双向绑定特征,当点击的时候,将文本加入列表当中
  • 利用了@click绑定函数
  • 利用了v-for的方式
  • 利用vue和变量的响应能力,当vue变量发生改变的时候,与其绑定的标签也会发生重新渲染

vue实例的生命周期

参考资料

vue当中挂载的含义 官方文档-vue应用的生命周期

相关概念

  • 钩子:钩子函数 其实钩子就类似于这种回调函数的形式,通过通知的方式告知,某个动作要执行了
  • 挂载:参考上面的资料

vue的整体流程

我们可以看到官方提供了很多的钩子函数,这样我们可以在这些时候进行一些操作

<template>
	<view class="content">
		<button type="primary" @click="click">改变</button>
		<view class="">
			{{text}}
		</view>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				text:'hello'
			}
		},
		onLoad() {
		},
		methods: {
			click(){
				this.text = "你好"
			}
		},
		beforeCreate(){
			// 在创建之前是没有data里面的数据的,所以打印出来的是undefined
			console.log(this.text)
		},
		created(){
			console.log(this.text)
		},
		beforeMount() {
			console.log(1)
		},
		// mounted 挂载其实就是页面渲染到应该有的位置
		mounted() {
			console.log(2)
		},
		beforeUpdate() {
			// 在更新的时候进行
			console.log("beforeUpdate")
		},
		updated(){
			console.log("Updated")
		}
	}
</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>

上面是我们使用一些钩子函数的实例以及注释,这样我们就可以使用一些操作

计算属性、方法和监听

计算属性
  • 当我们修改计算属性当中使用的变量的时候,会重新调用计算属性然后重新渲染页面
  • 当我们修改与计算属性(函数)无关的变量的时候,则不会重新调用计算属性
<template>
	<view class="">
		{{fullText}}
		<button type="primary" @click="click">按钮</button>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				firstTest:'hello',
				lastText:'world'
			}
		},
		onLoad() {
		},
		methods: {
			click(){
				this.firstTest = 'tt'
			}
		},
		computed:{
			fullText(){
				console.log("计算属性")
				// 当我们修改属性之后,再次调用这个属性,但是如果我们修改和当前计算属性不相关的变量的时候
				// 则不会重复调用
				return this.firstTest + " " + this.lastText
			}
		}
	}
</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>

但是如果我们使用一个普通的函数(在methods当中定义)的函数呢?

方法
  • 使用方法由于其无论改变哪个变量(有关和无关)都会重新调用,这样会降低性能
  • 调用方法需要加()
<template>
	<view class="">
		{{fullText()}}
		<button type="primary" @click="click">按钮</button>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				firstTest:'hello',
				lastText:'world'
			}
		},
		onLoad() {
		},
		methods: {
			click(){
				this.firstTest = 'tt'
			},
			fullText(){
				console.log("方法")
				return this.firstTest+ " " + this.lastText
			}
		}
	}
</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>

监听
  • 监听是对某一变量的监听,其名称等于需要被监听的变量的名称
  • 当变量发生改变的时候会调用监听,然后重新进行渲染

代码如下:

<template>
	<view class="">
		{{fullText}}
		<button type="primary" @click="click">按钮</button>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				firstText:'hello',
				lastText:'world',
				fullText: "hello world"
			}
		},
		onLoad() {
		},
		methods: {
			click(){
				this.firstText = 'tt'
			}
		},
		watch:{
			firstText(){
				console.log("first")
				this.fullText = this.firstText + " " + this.lastText
			},
			lastText(){
				console.log("last")
				this.fullText = this.firstText + " " + this.lastText
			}
		}
	}
</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>

对于上面的代码我们就监听了两个变量,当firstText发生改变的时候会调用firstText的监听函数

父子组件传值

  • 创建组件在components里面,这里起名为child,然后引用,在页面的script里面使用import和components指令,得到结果
<template>
	<view class="">
		<child></child>
	</view>
</template>

<script>
	import child from '../../components/child.vue'
	export default {
		components:{
			child
		},
		data() {
			return {};
		},
		onLoad() {
		},
		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>

关于命名的问题

如果我们命名一个组件的名称是chiLd,那么我们在调用组件的时候就需要使用chi-ld,代码如下:

<template>
	<view class="">
		<chi-ld></chi-ld>
	</view>
</template>

<script>
	import chiLd from '../../components/child.vue'
	export default {
		components:{
			chiLd
		},
		data() {
			return {};
		},
		onLoad() {
		},
		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>

此时我们就可以实现这些操作

父子组件传值

这里直接用两段代码来直接说明

父组件

<template>
	<view class="">
		<!-- 这里也是监听到我们emit过来的change事件,此时会向test函数当中传入一个变量,就是我们emit过来的那个变量title,作为形参res -->
		<child @change="changeFather" :text="text" :hello="test"></child>
		{{title}}
	</view>
</template>

<script>
	import child from '../../components/child.vue'
	export default {
		components:{
			child
		},
		data() {
			return {
				test:"我是hello",
				text:'我是父组件',
				title:"我是父组件"
			};
		},
		onLoad() {
		},
		methods: {
			changeFather(res){
				console.log(res)
				this.title = res
			}
		}
	}
</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>

子组件

<template>
	<view>
		{{text}}
		{{hello}}
		<button type="primary" @click="click">传值</button>
	</view>
</template>

<script>
	export default {
		name:"child",
		props:['text','hello'], // 用来接收父组件传给子组件的数据
		data() {
			return {
				title:"我是子组件"
			};
		},
		methods:{
			click(){
				// click触发一个事件,然后传递值到父组件当中
				this.$emit('change', this.title)
			}
		}
	}
</script>

<style>

</style>

从上面的代码看出两种的基本步骤:

利用父组件传递给子组件:

  1. 在父组件当中定义变量(假设为text)
  2. 然后我们在调用的child标签当中加入一个属性 ':子组件当中接收的变量名 : "text"'
  3. 然后我们在子组件当中声明一个props数组,然后存储形式为 props : ['子组件当中接收的变量名1','子组件当中接收的变量名2',....]
  4. 此时就可以在组件当中将这些变量名当作一般的变量使用,利用模板语法等就可以进行操作

利用子组件传递给父组件:

  1. 在子组件当中定义变量(假设为title)
  2. 定义一个方法,然后让方法绑定某个事件名称,上面的测试样例当中使用的是change,绑定使用的是click函数,利用$emit("change",this.title)传入
  3. 事件的名称就是change了,然后我们需要在父组件当中定义child的地方来进行,将change作为一个属性 $change: "click",这样的话,我们利用上面emit传入的参数this.title就可以作为参数传入click函数。
  4. 按照上面的方法就可以实现传值

组件参数校验

在子组件对父组件当中的变量进行约束,限制变量类型等

<template>
	<view>
		{{text}}
		{{hello}}
		<button type="primary" @click="click">传值</button>
	</view>
</template>

<script>
	export default {
		name:"child",
		// 用来接收父组件传给子组件的数据
		// 进行约束
		props:{
			// 可以有多种形式进行约束
			'text' : [String, Number],
			'hello': {
				type:String
				default:3  // 这里可以设置为一个默认值
			}
		}, 
		data() {
			return {
				title:"我是子组件"
			};
		},
		methods:{
			click(){
				// click触发一个事件,然后传递值到父组件当中
				this.$emit('change', this.title)
			}
		}
	}
</script>

<style>

</style>

按照上面的多种形式都可以进行约束,当然也可以就一个值,也是可以的。