跟着尚硅谷学vue2—进阶版1.0—组件化编程

2. Vue 组件化编程

1. 传统方式和使用组件方式编写的对比

1. 传统方式编写应用

27

2. 使用组件方式编写应用

28

29

30

2. 模块与组件、模块化与组件化

1. 模块
  1. 理解: 向外提供特定功能的 js 程序, 一般就是一个 js 文件
  2. 为什么: js 文件很多很复杂
  3. 作用: 复用 js, 简化 js 的编写, 提高 js 运行效率
2. 组件
  1. 理解: 用来实现局部(特定)功能效果的代码集合(html/css/js/image……)
  2. 为什么: 一个界面的功能很复杂
  3. 作用: 复用编码, 简化项目编码, 提高运行效率
3. 模块化

当应用中的 js 都以模块来编写的, 那这个应用就是一个模块化的应用。 (把js按照模块化的标准拆分成好几个js)

4. 组件化

当应用中的功能都是多组件的方式来编写的, 那这个应用就是一个组件化的应用,。(应用按照功能点进行拆分,不同的功能点是一个不同的组件)

5. 例子

33

3. 组件的两种编写形式

1. 组件基础
  1. 非单文件组件

    31

  2. 单文件组件

    32

2. 非单文件组件
  1. 模板编写没有提示
  2. 没有构建过程, 无法将 ES6 转换成 ES5
  3. 不支持组件的 CSS
  4. 真正开发中几乎不用
1. 基本使用

Vue中使用组件的三大步骤:

​ 一、定义组件(创建组件)

​ 二、注册组件

​ 三、使用组件(写组件标签)

  1. 如何定义一个组件?

    1. 使用Vue.extend(options)创建,其中options和new Vue(options)时传入的那个options几乎一样,但也有点区别;
      1. 区别如下:
        1. el不要写,为什么? ——— 最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器。
        2. data必须写成函数,为什么? ———— 避免组件被复用时,数据存在引用关系。
      2. 备注:使用template可以配置组件结构。
  2. 如何注册组件?

    1. 局部注册:靠new Vue的时候传入components选项
    2. 全局注册:靠Vue.component(‘组件名’,组件)
  3. 编写组件标签:

    <school></school>

<body>
	<!-- 准备好一个容器-->
	<div id="root">
		<hello></hello>
		<hr>
		<h1>{{msg}}</h1>
		<hr>
		<!-- 第三步:编写组件标签 -->
		<school></school>
		<hr>
		<!-- 第三步:编写组件标签 -->
		<student></student>
	</div>

	<div id="root2">
		<hello></hello>
	</div>
</body>

<script type="text/javascript">
	Vue.config.productionTip = false

	//第一步:创建school组件
	const school = Vue.extend({
		template: `
				<div class="demo">
					<h2>学校名称:{{schoolName}}</h2>
					<h2>学校地址:{{address}}</h2>
					<button @click="showName">点我提示学校名</button>	
				</div>
			`,
		// el:'#root', //组件定义时,一定不要写el配置项,因为最终所有的组件都要被一个vm管理,由vm决定服务于哪个容器。
		data() {
			return {
				schoolName: '尚硅谷',
				address: '北京昌平'
			}
		},
		methods: {
			showName() {
				alert(this.schoolName)
			}
		},
	})

	//第一步:创建student组件
	const student = Vue.extend({
		template: `
				<div>
					<h2>学生姓名:{{studentName}}</h2>
					<h2>学生年龄:{{age}}</h2>
				</div>
			`,
		data() {
			return {
				studentName: '张三',
				age: 18
			}
		}
	})

	//第一步:创建hello组件
	const hello = Vue.extend({
		template: `
				<div>	
					<h2>你好啊!{{name}}</h2>
				</div>
			`,
		data() {
			return {
				name: 'Tom'
			}
		}
	})

	//第二步:全局注册组件
	Vue.component('hello', hello)

	//创建vm
	new Vue({
		el: '#root',
		data: {
			msg: '你好啊!'
		},
		//第二步:注册组件(局部注册)
		components: {
			school,
			student
		}
	})

	new Vue({
		el: '#root2',
	})
</script>

2. 几个注意点
  1. 关于组件名:

    1. 一个单词组成:
      1. 第一种写法(首字母小写):school
      2. 第二种写法(首字母大写):School
    2. 多个单词组成:
      1. 第一种写法(kebab-case命名):my-school
      2. 第二种写法(CamelCase命名):MySchool (需要Vue脚手架支持)
    3. 备注:
      1. 组件名尽可能回避HTML中已有的元素名称,例如:h2、H2都不行。
      2. 可以使用name配置项指定组件在开发者工具中呈现的名字。
  2. 关于组件标签:

    1. 第一种写法:<school></school>
    2. 第二种写法:<school/>
    3. 备注:不用使用脚手架时,<school/>会导致后续组件不能渲染。
  3. 一个简写方式:

    const school = Vue.extend(options) 可简写为:const school = options
    
    
<body>
	<div id="root">
		<h1>{{msg}}</h1>
		<school></school>
	</div>
</body>

<script type="text/javascript">
	Vue.config.productionTip = false

	//定义组件
	const s = Vue.extend({
		name: 'atguigu',
		template: `
				<div>
					<h2>学校名称:{{name}}</h2>	
					<h2>学校地址:{{address}}</h2>	
				</div>
			`,
		data() {
			return {
				name: '尚硅谷',
				address: '北京'
			}
		}
	})

    // 简写为:
	// const s = { // 如果我们编写没带extend,那么vue源码会帮我们补一个,所以我们写不写都可以,在使用脚手架的情况下,我们一般使用简写
	// 	name:'atguigu',
	// 	template:`
	// 		<div>
	// 			<h2>学校名称:{{name}}</h2>	
	// 			<h2>学校地址:{{address}}</h2>	
	// 		</div>
	// 	`,
	// 	data(){
	// 		return {
	// 			name:'尚硅谷',
	// 			address:'北京'
	// 		}
	// 	}
	// }
	new Vue({
		el: '#root',
		data: {
			msg: '欢迎学习Vue!'
		},
		components: {
			school: s
		}
	})
</script>

3. 组件的嵌套
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>组件的嵌套</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

		//定义student组件
		const student = Vue.extend({
			name:'student',
			template:`
				<div>
					<h2>学生姓名:{{name}}</h2>	
					<h2>学生年龄:{{age}}</h2>	
				</div>
			`,
			data(){
				return {
					name:'尚硅谷',
					age:18
				}
			}
		})
		
		//定义school组件
		const school = Vue.extend({
			name:'school',
			template:`
				<div>
					<h2>学校名称:{{name}}</h2>	
					<h2>学校地址:{{address}}</h2>	
					<student></student>
				</div>
			`,
			data(){
				return {
					name:'尚硅谷',
					address:'北京'
				}
			},
			//注册组件(局部)
			components:{
				student
			}
		})

		//定义hello组件
		const hello = Vue.extend({
			template:`<h1>{{msg}}</h1>`,
			data(){
				return {
					msg:'欢迎来到尚硅谷学习!'
				}
			}
		})
		
		//定义app组件
		const app = Vue.extend({
			template:`
				<div>	
					<hello></hello>
					<school></school>
				</div>
			`,
			components:{
				school,
				hello
			}
		})

		//创建vm
		new Vue({
			template:'<app></app>',
			el:'#root',
			//注册组件(局部)
			components:{app}
		})
	</script>
</html>

26

4. VueComponent

关于VueComponent:

  1. school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的。

  2. 我们只需要写<school/><school></school>,Vue解析时会帮我们创建school组件的实例对象,

    即Vue帮我们执行的:new VueComponent(options)。

  3. 特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent!!!!

  4. 关于this指向:

    1. 组件配置中:
      1. data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【VueComponent实例对象】。
    2. new Vue(options)配置中:
      1. data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【Vue实例对象】。
  5. VueComponent的实例对象,以后简称vc(也可称之为:组件实例对象)。

    1. Vue的实例对象,以后简称vm。
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>VueComponent</title>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<school></school>
			<hello></hello>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false
		
		//定义school组件
		const school = Vue.extend({
			name:'school',
			template:`
				<div>
					<h2>学校名称:{{name}}</h2>	
					<h2>学校地址:{{address}}</h2>	
					<button @click="showName">点我提示学校名</button>
				</div>
			`,
			data(){
				return {
					name:'尚硅谷',
					address:'北京'
				}
			},
			methods: {
				showName(){
					console.log('showName',this)
				}
			},
		})

		const test = Vue.extend({
			template:`<span>atguigu</span>`
		})

		//定义hello组件
		const hello = Vue.extend({
			template:`
				<div>
					<h2>{{msg}}</h2>
					<test></test>	
				</div>
			`,
			data(){
				return {
					msg:'你好啊!'
				}
			},
			components:{test}
		})


		// console.log('@',school)
		// console.log('#',hello)

		//创建vm
		const vm = new Vue({
			el:'#root',
			components:{school,hello}
		})
	</script>
</html>

5. Vue实例与组件实例

Vue实例(vm)与组件实例(vc)的区别:

其实 vm 和 vc 本质都是一个组件而已,大家的属性基本是一样的

但是 vm 会比 vc 多出el和router属性,vm可以通过el 指定容器到底为谁所用,但是vc不能写 el 指定容器为谁服务,他只能跟着 vm 走,而且 vc 的data会被要求 必须是函数 ,防止出现 同种组件多实例共享同一个data的事情

Vue实例与组件实例_子非鱼焉非我所愿的博客-优快云博客_vue组件和vue实例关系描述

vue实例的高逼格写法:

import App from 'app';

new Vue({
render: h =>h(App)
}).$mount('#app')

我们经常写出一些整个应用就只有一个组件。

所以为了方便,

原来的 template、components ------变成------> render: h=>h(App)

原来的 el ------变成------> .$mount(‘#app’)

ps: mount是挂载的意思

值得注意的是里面的methods

我们千万不要把里面的方法写成箭头函数的形式

因为我们避免不了在这些方法里面写this,若写成箭头函数,this的指向就会变成 未被编译成vue对象的这个配置obj

6. 一个重要的内置关系
1. 补充知识点:显式原型属性和隐式原型
  • 什么是原型

    • 每一个构造函数(可以理解为类)都拥有一个属性(prototype),该属性指向一个对象,用于存放公共的属性和方法。 构造函数的定义方式:

      var Fun=new Function()
      Function Fun(){} 
      //Fun就是创建出来的构造函数 
      
      
  • 为什么要用原型

    • 虽然常说js中一切皆对象,但js本身不是一项面向对象编程的语言,没有类(class)的说法, 所以说为了让构造函数(Function fun())构造出来的对象拥有公共的属性和方法, 故js使用原型(prototyoe)来存储这些公共的属性和方法`在这里插入代码片
  • 如何使用原型

    • 定义

      Fun.prototype.num = 520;  //添加公共属性
      Fun.prototype.getPrice = function() {
          return `price:${this.num}`
      } 
      
      
    • 使用

      var fun=new Fun()
      fun.num;
      fun.getPrice()
      
      
  • 显示原型和隐式原型?

    • 显示原型:Fun是构造函数(可以理解为类),Function上的prototype的属性
    • 隐式原型:fun是由构造函数new出来的对象,fun中的__proto__是fun的属性
    • 关联:fun的隐式原型指向Fun构造函数的显示原型
  • 基于原型的执行方法

    • 当我们尝试获取实例(new出来的对象)的属性和方式时,首先会在本身的属性和方法中进行查找,找不到的话就通过隐式原型找到显示原型(也就是找到创造这个对象的类),去这里原型上的属性和方法,找不到就会顺着原型链一直向上,如果再找不到的话Object.__proto__就会抛出underfind,原因是就是因为Object.__proto__永远指向null。
  • 每个class都有显示原型prototype

  • 每个实例都会有隐式原型__proto__

  • 实例的隐式原型(__proto__)对应class的显示原型(prototype)

  • hasOwnProperty 寻找自身属性值是否包含该属性

  • instanceof 寻找自身原型链中是否包含该属性 ( instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。 )

  • 所有的引用类型instanceof Object返回的都是true

    [] instanceof Array //true 
    [] instanceof Object //true
    {} instance Object //true
    
    

25

2. 分析Vue与VueComponent的关系
  1. 一个重要的内置关系:VueComponent.prototype.proto === Vue.prototype

    24

  2. 为什么要有这个关系:让组件实例对象(vc)可以访问到 Vue原型上的属性、方法。

23

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>一个重要的内置关系</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<school></school>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
		Vue.prototype.x = 99

		//定义school组件
		const school = Vue.extend({
			name:'school',
			template:`
				<div>
					<h2>学校名称:{{name}}</h2>	
					<h2>学校地址:{{address}}</h2>	
					<button @click="showX">点我输出x</button>
				</div>
			`,
			data(){
				return {
					name:'尚硅谷',
					address:'北京'
				}
			},
			methods: {
				showX(){
					console.log(this.x)
				}
			},
		})

		//创建一个vm
		const vm = new Vue({
			el:'#root',
			data:{
				msg:'你好'
			},
			components:{school}
		})

		
		//定义一个构造函数
		/* function Demo(){
			this.a = 1
			this.b = 2
		}
		//创建一个Demo的实例对象
		const d = new Demo()

		console.log(Demo.prototype) //显示原型属性

		console.log(d.__proto__) //隐式原型属性

		console.log(Demo.prototype === d.__proto__)

		//程序员通过显示原型属性操作原型对象,追加一个x属性,值为99
		Demo.prototype.x = 99

		console.log('@',d) */

	</script>
</html>

3.单文件组件
1. 一个 .vue 文件的组成(3 个部分)
  1. 模板页面

    <template>
    	<!-- 页面模板 -->
    </template>
    
    
  2. JS 模块对象

    <script>
    export default {
        data() {
            return {}
        }, 
        methods: {}, 
        computed: {}, 
        components: {}
    }
    </script>
    
    
  3. 样式

    <style>
        // 样式定义
    </style>
    
    
2. 基本使用
  1. 引入组件
  2. 映射成标签
  3. 使用组件标签
3. 例子
  1. 入口文件

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="UTF-8" />
    		<title>练习一下单文件组件的语法</title>
    	</head>
    	<body>
    		<!-- 准备一个容器 -->
    		<div id="root"></div>
    		<script type="text/javascript" src="../js/vue.js"></script>
    		<script type="text/javascript" src="./main.js"></script>
    	</body>
    </html>
    
    
    
  2. App组件

    <template>
    	<div>
    		<School></School>
    		<Student></Student>
    	</div>
    </template>
    
    <script>
    	//引入组件
    	import School from './School.vue'
    	import Student from './Student.vue'
    
    	export default {
    		name:'App',
    		components:{
    			School,
    			Student
    		}
    	}
    </script>
    
    
  3. 绑定vm文件

    import App from './App.vue'
    
    new Vue({
    	el:'#root',
    	template:`<App></App>`,
    	components:{App},
    })
    
    
  4. School组件

    <template>
    	<div class="demo">
    		<h2>学校名称:{{name}}</h2>
    		<h2>学校地址:{{address}}</h2>
    		<button @click="showName">点我提示学校名</button>	
    	</div>
    </template>
    
    <script>
    	 export default {
    		name:'School',
    		data(){
    			return {
    				name:'尚硅谷',
    				address:'北京昌平'
    			}
    		},
    		methods: {
    			showName(){
    				alert(this.name)
    			}
    		},
    	}
    </script>
    
    <style>
    	.demo{
    		background-color: orange;
    	}
    </style>
    
    
  5. Student组件

    <template>
    	<div>
    		<h2>学生姓名:{{name}}</h2>
    		<h2>学生年龄:{{age}}</h2>
    	</div>
    </template>
    
    <script>
    	 export default {
    		name:'Student',
    		data(){
    			return {
    				name:'张三',
    				age:18
    			}
    		}
    	}
    </script>
    
    
    
  6. 注意,上面的所有文件只有放在脚手架里才能使用,不能直接使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值