Vue第三天学习笔记之组件化开发

Posted 最小的帆也能远航

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue第三天学习笔记之组件化开发相关的知识,希望对你有一定的参考价值。

目录

 

1.JavaScript高阶函数的使用

2.v-model使用

2.1v-model的基本使用

2.2v-model的原理

2.3v-model结合radio类型

2.4v-model结合checkbox类型

2.5v-model结合select类型

2.6v-model修饰符的使用

3.组件化开发

3.1组件化的基本使用

3.2全局组件和局部组件

3.3父组件和子组件

3.4组件的语法糖注册方式

3.5组件模板的分离写法

3.6组件中的数据存放问题

3.7组件中的data为什么是函数

3.8组件通信-父组件向子组件传递数据

3.9组件通信-父传子(props中的驼峰标识)

3.10组件通信-子传父(自定义事件)


1.javascript高阶函数的使用

const app = new Vue({
	el: '#app',
	data: {
		books: [{
				id: 1,
				name: '《算法导论》',
				date: '2006-9',
				price: 85.00,
				count: 1
			},
			{
				id: 2,
				name: '《UNIX编程艺术》',
				date: '2006-2',
				price: 59.00,
				count: 1
			},
			{
				id: 3,
				name: '《编程珠玑》',
				date: '2008-10',
				price: 39.00,
				count: 1
			},
			{
				id: 4,
				name: '《代码大全》',
				date: '2006-3',
				price: 128.00,
				count: 1
			},
		]
	},
	methods: {
		// getFinalPrice(price) {
		//   return '¥' + price.toFixed(2)
		// }
		increment(index) {
			this.books[index].count++
		},
		decrement(index) {
			this.books[index].count--
		},
		removeHandle(index) {
			this.books.splice(index, 1)
		}
	},
	computed: {
		totalPrice() {
			// 1.普通的for循环
			// let totalPrice = 0
			// for (let i = 0; i < this.books.length; i++) {
			//   totalPrice += this.books[i].price * this.books[i].count
			// }
			// return totalPrice

			// 2.for (let i in this.books)
			// let totalPrice = 0
			// for (let i in this.books) {
			//   const book = this.books[i]
			//   totalPrice += book.price * book.count
			// }
			//
			// return totalPrice

			// 3.for (let i of this.books)
			// let totalPrice = 0
			// for (let item of this.books) {
			//   totalPrice += item.price * item.count
			// }
			// return totalPrice

			return this.books.reduce(function(preValue, book) {
				return preValue + book.price * book.count
			}, 0)
		}
	},
	filters: {
		showPrice(price) {
			return '¥' + price.toFixed(2)
		}
	}
})

2.v-model使用

2.1v-model的基本使用

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8">
		<title>Title</title>
	</head>
	<body>

		<div id="app">
			<input type="text" v-model="message">
			{{message}}
		</div>

		<script src="../js/vue.js"></script>
		<script>
			const app = new Vue({
				el: '#app',
				data: {
					message: '你好啊'
				}
			})
		</script>

	</body>
</html>

2.2v-model的原理

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8">
		<title>Title</title>
	</head>
	<body>

		<div id="app">
			<!--<input type="text" v-model="message">-->
			<!--<input type="text" :value="message" @input="valueChange">-->
			<input type="text" :value="message" @input="message = $event.target.value">
			<h2>{{message}}</h2>
		</div>

		<script src="../js/vue.js"></script>
		<script>
			const app = new Vue({
				el: '#app',
				data: {
					message: '你好啊'
				},
				methods: {
					valueChange(event) {
						this.message = event.target.value;
					}
				}
			})
		</script>

	</body>
</html>

2.3v-model结合radio类型

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8">
		<title>Title</title>
	</head>
	<body>

		<div id="app">
			<label for="male">
				<input type="radio" id="male" value="男" v-model="sex">男
			</label>
			<label for="female">
				<input type="radio" id="female" value="女" v-model="sex">女
			</label>
			<h2>您选择的性别是: {{sex}}</h2>
		</div>

		<script src="../js/vue.js"></script>
		<script>
			const app = new Vue({
				el: '#app',
				data: {
					message: '你好啊',
					sex: '女'
				}
			})
		</script>

	</body>
</html>

 

2.4v-model结合checkbox类型

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8">
		<title>Title</title>
	</head>
	<body>

		<div id="app">
			<!--1.checkbox单选框-->
			<!--<label for="agree">-->
			<!--<input type="checkbox" id="agree" v-model="isAgree">同意协议-->
			<!--</label>-->
			<!--<h2>您选择的是: {{isAgree}}</h2>-->
			<!--<button :disabled="!isAgree">下一步</button>-->

			<!--2.checkbox多选框-->
			<input type="checkbox" value="篮球" v-model="hobbies">篮球
			<input type="checkbox" value="足球" v-model="hobbies">足球
			<input type="checkbox" value="乒乓球" v-model="hobbies">乒乓球
			<input type="checkbox" value="羽毛球" v-model="hobbies">羽毛球
			<h2>您的爱好是: {{hobbies}}</h2>

			<label v-for="item in originHobbies" :for="item">
				<input type="checkbox" :value="item" :id="item" v-model="hobbies">{{item}}
			</label>
		</div>

		<script src="../js/vue.js"></script>
		<script>
			const app = new Vue({
				el: '#app',
				data: {
					message: '你好啊',
					isAgree: false, // 单选框
					hobbies: [], // 多选框,
					originHobbies: ['篮球', '足球', '乒乓球', '羽毛球', '台球', '高尔夫球']
				}
			})
		</script>

	</body>
</html>

2.5v-model结合select类型

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8">
		<title>Title</title>
	</head>
	<body>

		<div id="app">
			<!--1.选择一个-->
			<select name="abc" v-model="fruit">
				<option value="苹果">苹果</option>
				<option value="香蕉">香蕉</option>
				<option value="榴莲">榴莲</option>
				<option value="葡萄">葡萄</option>
			</select>
			<h2>您选择的水果是: {{fruit}}</h2>

			<!--2.选择多个-->
			<select name="abc" v-model="fruits" multiple>
				<option value="苹果">苹果</option>
				<option value="香蕉">香蕉</option>
				<option value="榴莲">榴莲</option>
				<option value="葡萄">葡萄</option>
			</select>
			<h2>您选择的水果是: {{fruits}}</h2>
		</div>

		<script src="../js/vue.js"></script>
		<script>
			const app = new Vue({
				el: '#app',
				data: {
					message: '你好啊',
					fruit: '香蕉',
					fruits: []
				}
			})
		</script>

	</body>
</html>

2.6v-model修饰符的使用

lazy修饰符:

  • 默认情况下,v-model默认是在input事件中同步输入框的数据的。
  • 也就是说,一旦有数据发生改变对应的data中的数据就会自动发生改变。
  • lazy修饰符可以让数据在失去焦点或者回车时才会更新:

number修饰符:

  • 默认情况下,在输入框中无论我们输入的是字母还是数字,都会被当做字符串类型进行处理。
  • 但是如果我们希望处理的是数字类型,那么最好直接将内容当做数字处理。
  • number修饰符可以让在输入框中输入的内容自动转成数字类型:

trim修饰符:

  • 如果输入的内容首尾有很多空格,通常我们希望将其去除
  • trim修饰符可以过滤内容左右两边的空格
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8">
		<title>Title</title>
	</head>
	<body>

		<div id="app">
			<!--1.修饰符: lazy-->
			<input type="text" v-model.lazy="message">
			<h2>{{message}}</h2>


			<!--2.修饰符: number-->
			<input type="number" v-model.number="age">
			<h2>{{age}}-{{typeof age}}</h2>

			<!--3.修饰符: trim-->
			<input type="text" v-model.trim="name">
			<h2>您输入的名字:{{name}}</h2>
		</div>

		<script src="../js/vue.js"></script>
		<script>
			const app = new Vue({
				el: '#app',
				data: {
					message: '你好啊',
					age: 0,
					name: ''
				}
			})

			var age = 0
			age = '1111'
			age = '222'
		</script>

	</body>
</html>


3.组件化开发

人面对复杂问题的处理方式:

  • 任何一个人处理信息的逻辑能力都是有限的
  • 所以,当面对一个非常复杂的问题时,我们不太可能一次性搞定一大堆的内容。
  • 但是,我们人有一种天生的能力,就是将问题进行拆解。
  • 如果将一个复杂的问题,拆分成很多个可以处理的小问题,再将其放在整体当中,你会发现大的问题也会迎刃而解。 组件化也是类似的思想: 如果我们将一个页面中所有的处理逻辑全部放在一起,处理起来就会变得非常复杂,而且不利于后续的管理以及扩展。 但如果,我们讲一个页面拆分成一个个小的功能块,每个功能块完成属于自己这部分独立的功能,那么之后整个页面的管理和维护就变得非常容易了

Vue组件化思想

组件化是Vue.js中的重要思想

  • 它提供了一种抽象,让我们可以开发出一个个独立可复用的小组件来构造我们的应用。
  • 任何的应用都会被抽象成一颗组件树。

组件化思想的应用:

  • 有了组件化的思想,我们在之后的开发中就要充分的利用它。
  • 尽可能的将页面拆分成一个个小的、可复用的组件。
  • 这样让我们的代码更加方便组织和管理,并且扩展性也更强。

3.1组件化的基本使用

组件的使用分成三个步骤:

  • 创建组件构造器
  • 注册组件
  • 使用组件
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8">
		<title>Title</title>
	</head>
	<body>

		<div id="app">
			<!--3.使用组件-->
			<my-cpn></my-cpn>
			<my-cpn></my-cpn>
			<my-cpn></my-cpn>
			<my-cpn></my-cpn>

			<div>
				<div>
					<my-cpn></my-cpn>
				</div>
			</div>
		</div>

		<my-cpn></my-cpn>

		<script src="../js/vue.js"></script>
		<script>
			// 1.创建组件构造器对象
			const cpnC = Vue.extend({
				template: `
      <div>
        <h2>我是标题</h2>
        <p>我是内容, 哈哈哈哈</p>
        <p>我是内容, 呵呵呵呵</p>
      </div>`
			})

			// 2.注册组件
			Vue.component('my-cpn', cpnC)

			const app = new Vue({
				el: '#app',
				data: {
					message: '你好啊'
				}
			})
		</script>

	</body>
</html>

1.Vue.extend():

  • 调用Vue.extend()创建的是一个组件构造器。
  • 通常在创建组件构造器时,传入template代表我们自定义组件的模板。
  • 该模板就是在使用到组件的地方,要显示的HTML代码。
  • 事实上,这种写法在Vue2.x的文档中几乎已经看不到了,它会直接使用下面我们会讲到的语法糖,但是在很多资料还是会提到这种方式,而且这种方式是学习后面方式的基础。

2.Vue.component():

  • 调用Vue.component()是将刚才的组件构造器注册为一个组件,并且给它起一个组件的标签名称。
  • 所以需要传递两个参数:1、注册组件的标签名 2、组件构造器

3.组件必须挂载在某个Vue实例下,否则它不会生效。(见下页)

  • 我们来看下面我使用了三次<my-cpn></my-cpn>
  • 而第三次其实并没有生效:

3.2全局组件和局部组件

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8">
		<title>Title</title>
	</head>
	<body>

		<div id="app">
			<cpn></cpn>
			<cpn></cpn>
			<cpn></cpn>
		</div>

		<div id="app2">
			<cpn></cpn>
		</div>

		<script src="../js/vue.js"></script>
		<script>
			// 1.创建组件构造器
			const cpnC = Vue.extend({
				template: `
      <div>
        <h2>我是标题</h2>
        <p>我是内容,哈哈哈哈啊</p>
      </div>
    `
			})

			// 2.注册组件(全局组件, 意味着可以在多个Vue的实例下面使用)
			// Vue.component('cpn', cpnC)

			// 疑问: 怎么注册的组件才是局部组件了?

			const app = new Vue({
				el: '#app',
				data: {
					message: '你好啊'
				},
				components: {
					// cpn使用组件时的标签名
					cpn: cpnC
				}
			})

			const app2 = new Vue({
				el: '#app2'
			})
		</script>

	</body>
</html>

 

3.3父组件和子组件

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8">
		<title>Title</title>
	</head>
	<body>

		<div id="app">
			<cpn2></cpn2>
			<!--<cpn1></cpn1>-->
		</div>

		<script src="../js/vue.js"></script>
		<script>
			// 1.创建第一个组件构造器(子组件)
			const cpnC1 = Vue.extend({
				template: `
      <div>
        <h2>我是标题1</h2>
        <p>我是内容, 哈哈哈哈</p>
      </div>
    `
			})


			// 2.创建第二个组件构造器(父组件)
			const cpnC2 = Vue.extend({
				template: `
      <div>
        <h2>我是标题2</h2>
        <p>我是内容, 呵呵呵呵</p>
        <cpn1></cpn1>
      </div>
    `,
				components: {
					cpn1: cpnC1
				}
			})

			// root组件
			const app = new Vue({
				el: '#app',
				data: {
					message: '你好啊'
				},
				components: {
					cpn2: cpnC2
				}
			})
		</script>

	</body>
</html>

3.4组件的语法糖注册方式

在上面注册组件的方式,可能会有些繁琐。

  • Vue为了简化这个过程,提供了注册的语法糖。
  • 主要是省去了调用Vue.extend()的步骤,而是可以直接使用一个对象来代替。
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8">
		<title>Title</title>
	</head>
	<body>

		<div id="app">
			<cpn1></cpn1>
			<cpn2></cpn2>
		</div>

		<script src="../js/vue.js"></script>
		<script>
			// 1.全局组件注册的语法糖
			// 1.创建组件构造器
			// const cpn1 = Vue.extend()

			// 2.注册组件
			Vue.component('cpn1', {
				template: `
      <div>
        <h2>我是标题1</h2>
        <p>我是内容, 哈哈哈哈</p>
      </div>
    `
			})

			// 2.注册局部组件的语法糖
			const app = new Vue({
				el: '#app',
				data: {
					message: '你好啊'
				},
				components: {
					'cpn2': {
						template: `
          <div>
            <h2>我是标题2</h2>
            <p>我是内容, 呵呵呵</p>
          </div>
    `
					}
				}
			})
		</script>

	</body>
</html>

3.5组件模板的分离写法

Vue提供了两种方案来定义HTML模块内容:

  • 使用<script>标签
  • 使用<template>标签
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8">
		<title>Title</title>
	</head>
	<body>

		<div id="app">
			<cpn></cpn>
			<cpn></cpn>
			<cpn></cpn>
		</div>

		<!--1.script标签, 注意:类型必须是text/x-template-->
		<!--<script type="text/x-template" id="cpn">-->
		<!--<div>-->
		<!--<h2>我是标题</h2>-->
		<!--<p>我是内容,哈哈哈</p>-->
		<!--</div>-->
		<!--</script>-->

		<!--2.template标签-->
		<template id="cpn">
			<div>
				<h2>我是标题</h2>
				<p>我是内容,呵呵呵</p>
			</div>
		</template>

		<script src="../js/vue.js"></script>
		<script>
			// 1.注册一个全局组件
			Vue.component('cpn', {
				template: '#cpn'
			})

			const app = new Vue({
				el: '#app',
				data: {
					message: '你好啊'
				}
			})
		</script>

	</body>
</html>

3.6组件中的数据存放问题

组件自己的数据存放在哪里呢?

  • 组件对象也有一个data属性(也可以有methods等属性,下面我们有用到)
  • 只是这个data属性必须是一个函数
  • 而且这个函数返回一个对象,对象内部保存着数据
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8">
		<title>Title</title>
	</head>
	<body>

		<div id="app">
			<cpn></cpn>
			<cpn></cpn>
			<cpn></cpn>
		</div>

		<!--1.script标签, 注意:类型必须是text/x-template-->
		<!--<script type="text/x-template" id="cpn">-->
		<!--<div>-->
		<!--<h2>我是标题</h2>-->
		<!--<p>我是内容,哈哈哈</p>-->
		<!--</div>-->
		<!--</script>-->

		<!--2.template标签-->
		<template id="cpn">
			<div>
				<h2>{{title}}</h2>
				<p>我是内容,呵呵呵</p>
			</div>
		</template>

		<script src="../js/vue.js"></script>
		<script>
			// 1.注册一个全局组件
			Vue.component('cpn', {
				template: '#cpn',
				data() {
					return {
						title: 'abc'
					}
				}
			})

			const app = new Vue({
				el: '#app',
				data: {
					message: '你好啊',
					// title: '我是标题'
				}
			})
		</script>

	</body>
</html>

3.7组件中的data为什么是函数

为什么data在组件中必须是一个函数呢?

  • 首先,如果不是一个函数,Vue直接就会报错。
  • 其次,原因是在于Vue让每个组件对象都返回一个新的对象,因为如果是同一个对象的,组件在多次使用后会相互影响。
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8">
		<title>Title</title>
	</head>
	<body>

		<!--组件实例对象-->
		<div id="app">
			<cpn></cpn>
			<cpn></cpn>
			<cpn></cpn>
		</div>

		<template id="cpn">
			<div>
				<h2>当前计数: {{counter}}</h2>
				<button @click="increment">+</button>
				<button @click="decrement">-</button>
			</div>
		</template>
		<script src="../js/vue.js"></script>
		<script>
			// 1.注册组件
			const obj = {
				counter: 0
			}
			Vue.component('cpn', {
				template: '#cpn',
				// data() {
				//   return {
				//     counter: 0
				//   }
				// },
				data() {
					return obj
				},
				methods: {
					increment() {
						this.counter++
					},
					decrement() {
						this.counter--
					}
				}
			})

			const app = new Vue({
				el: '#app',
				data: {
					message: '你好啊'
				}
			})
		</script>

		<script>
			// const obj = {
			//   name: 'why',
			//   age: 18
			// }
			//
			// function abc() {
			//   return obj
			// }
			//
			// let obj1 = abc()
			// let obj2 = abc()
			// let obj3 = abc()
			//
			// obj1.name = 'kobe'
			// console.log(obj2);
			// console.log(obj3);
		</script>

	</body>
</html>

3.8组件通信-父组件向子组件传递数据

在开发中,往往一些数据确实需要从上层传递到下层:

  • 比如在一个页面中,我们从服务器请求到了很多的数据。
  • 其中一部分数据,并非是我们整个页面的大组件来展示的,而是需要下面的子组件进行展示。
  • 这个时候,并不会让子组件再次发送一个网络请求,而是直接让大组件(父组件)将数据传递给小组件(子组件)。

如何进行父子组件间的通信呢?Vue官方提到

  • 通过props向子组件传递数据
  • 通过事件向父组件发送消息

真实的开发中,Vue实例和子组件的通信和父组件和子组件的通信过程是一样的

 

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8">
		<title>Title</title>
	</head>
	<body>

		<div id="app">
			<!--<cpn v-bind:cmovies="movies"></cpn>-->
			<!--<cpn cmovies="movies" cmessage="message"></cpn>-->

			<cpn :cmessage="message" :cmovies="movies"></cpn>
		</div>



		<template id="cpn">
			<div>
				<ul>
					<li v-for="item in cmovies">{{item}}</li>
				</ul>
				<h2>{{cmessage}}</h2>
			</div>
		</template>

		<script src="../js/vue.js"></script>
		<script>
			// 父传子: props
			const cpn = {
				template: '#cpn',
				// props: ['cmovies', 'cmessage'],
				props: {
					// 1.类型限制
					// cmovies: Array,
					// cmessage: String,

					// 2.提供一些默认值, 以及必传值
					cmessage: {
						type: String,
						default: 'aaaaaaaa',
						required: true
					},
					// 类型是对象或者数组时, 默认值必须是一个函数
					cmovies: {
						type: Array,
						default () {
							return []
						}
					}
				},
				data() {
					return {}
				},
				methods: {

				}
			}

			const app = new Vue({
				el: '#app',
				data: {
					message: '你好啊',
					movies: ['海王', '海贼王', '海尔兄弟']
				},
				components: {
					cpn
				}
			})
		</script>

	</body>
</html>

props的值有两种方式:

  • 方式一:字符串数组,数组中的字符串就是传递时的名称。
  • 方式二:对象,对象可以设置传递时的类型,也可以设置默认值等

3.9组件通信-父传子(props中的驼峰标识)

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8">
		<title>Title</title>
	</head>
	<body>

		<div id="app">
			<cpn :c-info="info" :child-my-message="message" v-bind:class></cpn>
		</div>

		<template id="cpn">
			<div>
				<h2>{{cInfo}}</h2>
				<h2>{{childMyMessage}}</h2>
			</div>
		</template>

		<script src="../js/vue.js"></script>
		<script>
			const cpn = {
				template: '#cpn',
				props: {
					cInfo: {
						type: Object,
						default () {
							return {}
						}
					},
					childMyMessage: {
						type: String,
						default: ''
					}
				}
			}

			const app = new Vue({
				el: '#app',
				data: {
					info: {
						name: 'why',
						age: 18,
						height: 1.88
					},
					message: 'aaaaaa'
				},
				components: {
					cpn
				}
			})
		</script>

	</body>
</html>

3.10组件通信-子传父(自定义事件)

什么时候需要自定义事件呢?

  • 当子组件需要向父组件传递数据时,就要用到自定义事件了。
  • 我们之前学习的v-on不仅仅可以用于监听DOM事件,也可以用于组件间的自定义事件。

自定义事件的流程:

  • 在子组件中,通过$emit()来触发事件。
  • 在父组件中,通过v-on来监听子组件事件。
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8">
		<title>Title</title>
	</head>
	<body>

		<!--父组件模板-->
		<div id="app">
			<cpn @item-click="cpnClick"></cpn>
		</div>

		<!--子组件模板-->
		<template id="cpn">
			<div>
				<button v-for="item in categories" @click="btnClick(item)">
					{{item.name}}
				</button>
			</div>
		</template>

		<script src="../js/vue.js"></script>
		<script>
			// 1.子组件
			const cpn = {
				template: '#cpn',
				data() {
					return {
						categories: [{
								id: 'aaa',
								name: '热门推荐'
							},
							{
								id: 'bbb',
								name: '手机数码'
							},
							{
								id: 'ccc',
								name: '家用家电'
							},
							{
								id: 'ddd',
								name: '电脑办公'
							},
						]
					}
				},
				methods: {
					btnClick(item) {
						// 发射事件: 自定义事件
						this.$emit('item-click', item)
					}
				}
			}

			// 2.父组件
			const app = new Vue({
				el: '#app',
				data: {
					message: '你好啊'
				},
				components: {
					cpn
				},
				methods: {
					cpnClick(item) {
						console.log('cpnClick', item);
					}
				}
			})
		</script>

	</body>
</html>

 

以上是关于Vue第三天学习笔记之组件化开发的主要内容,如果未能解决你的问题,请参考以下文章

3天学会Vue之基本知识(第三天:单文件组件(vue-cli)):结合项目开发经验,总结最关键的内容

vue2.0学习笔记之组件

学习Vue第三天

数学建模学习笔记集训十天之第三天

Python全栈开发学习笔记-03.第三天

Vue.js 2.0 由浅入深,第三天 day03