vue.js基础(4)

vue.js基础(4)

定义Vue组件

什么是组件:组件的出现,就是为了拆分Vue实例的代码量的,能够让我们以不同的组件,来划分不同的功能模块,将来我们需要什么样的功能就可以去调对应的组件即可

组件化和模块化的不同
  • 模块化:是从代码逻辑的角度进行划分的,方便代码分层开发,保证每个功能模块的职能单一
  • 组件化:是从UI界面的角度进行划分的,前端的组件化,方便UI组件的重用

全局组件定义的三种方式

1.使用Vue.extend配合Vue.component
2.直接使用Vue.component方法
3.将模板字符串,定义到script标签中

<!DOCTYPE html>
<html lang="en">

	<head>
		<meta charset="UTF-8">
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<meta http-equiv="X-UA-Compatible" content="ie=edge">
		<title>创建组件</title>
		<script src="vue-2.4.0.js"></script>
	</head>

	<body>
		<div id="app">
			<!-- 还是使用标签形式,引入自己的组件 -->
			<my-com1></my-com1>
		</div>
		<hr >
		<div id="app2">
			<my-com1></my-com1>
			<mycom2></mycom2>
		</div>
		<template id="tmp1">
			<h3>这是通过 template 元素,在外部定义的组件结构,这个方式有代码有提示和高亮</h3>
		</template>
		<script>
			// 1.1 使用Vue.extend 来创建全局的Vue组件
			// var com1 = Vue.extend({
                   // template:'<h3>5<sub>2<sub>这是使用Vue.extend 创建的组件5<sup>3<sup></h3>'   //通过 template 属性,指定了组件要展示的HTML结构 
			// })
			// 1.2 使用Vue.component('组件的名称',创建出来的组件模板对象)
			//如果使用Vue.component 定义全局组件的时候,组件名称使用了驼峰命名,则在引用组件的时候,需要把大写的驼峰改为小写的字母,同时,两个单词之间使用-链接
			// 如果不使用驼峰,则直接拿名称来使用即可
			// Vue.component('myCom1',com1)
			
			// Vue.component 第一个参数:组件的名称,将来在引用组件的时候,就是一个标签形式来引入它的
			// 第二个参数:Vue.extend 创建的组件,其中template 就是组件将来要展示的HTML 内容
			
			
				// 第一种创建组件的方式
			// Vue.component('myCom1',Vue.extend({
			// 	  template:'<h3>这是使用Vue.extend 创建的组件</h3>'
			// }))
			
			// 第二种创建组件方式
			// 注意:不论是哪种方式创建出来的组件,组件的template 属性指向的模板内容,必须有且只能有唯一的一个根元素
			// Vue.component('myCom1',{template:'<div><h3>这是直接使用 Vue.component 创建出来的组件</h3><span>123</span></div>'})
			
			// 第三种创建组件的方式
			Vue.component('myCom1',{
				template:'#tmp1'
			})
			
			
			
			var vm = new Vue({
				el: '#app',
				data: {},
				methods: {},
				
			});
			
			// 定义私有组件
			var vm = new Vue({
				// 控制区域
				el: '#app2',
				// 私有数据
				data: {},
				// 私有方法
				methods: {},
				// 私有组件
				components:{
					mycom2:
					{template:'<h3>这是私有组件</h3>'}
				},
				// 私有过滤器
				filters:{},
				// 自定义私有指令
				directives:{},
				
				
				// 生命周期函数
				beforeCreate(){},
				created(){},
				beforeMount(){},
				mounted(){},
				beforeUpdate(){},
				updated(){},
				beforeDestroy(){},
				destroyed(){
					
				}
			});
		</script>
	</body>

</html>

组件中展示数据和响应事件

1.在组价中,data需要被定义为一个方法
2.在组件中,如果将模板字符串,定义到了script标签中,那么,要访问子组件身上的data属性中的值,需要使用this来访问

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>组件中的data和methods</title>
    <script src="vue-2.4.0.js"></script>
</head>

<body>
    <div id="app">
		<mycom1></mycom1>
	</div>
    <script>
		// 1.组件可以有自己的data数据
		// 2.组件中的data和实例的data有点不一样,实例中的data可以为一个对象,但是组件中的data必须是一个方法
		// 3.组件中的data除了必须为一个方法之外,这个方法内部还必须返回一个对象才行
		// 4.组件中的data数据,使用方式和实例中的data使用方法完全一样!!!
		Vue.component('mycom1',
		{
			template:'<h1>这是全局组件-----{{msg}}</h1>',
			data:function(){
					
				return {
					msg:'这是组件中data定义的数据'
				}
			}
		})
		
		
        var vm=new Vue({
           el:'#app',
           data:{},
           methods:{}
        });
    </script>
</body>

</html>

【重点】为什么组件中的data属性必须定义为一个方法并返回一个对象

<!DOCTYPE html>
<html lang="en">

	<head>
		<meta charset="UTF-8">
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<meta http-equiv="X-UA-Compatible" content="ie=edge">
		<title>计数器</title>
		<script src="vue-2.4.0.js"></script>
	</head>

	<body>
		<!-- 需求:解释为什么组件中的data数据需要返回一个对象 -->
		<div id="app">
			<mycom1></mycom1>
			<hr>
			<mycom1></mycom1>
			<hr>
			<mycom1></mycom1>
			<hr>
			<mycom1></mycom1>
		</div>

		<template id="tmp">
			<div id="">
				<input type="button" name="" id="" value="+1" @click="add" />
				<h3>{{count}}</h3>
			</div>
		</template>
		<script>
			// 创建一个对象
			var dataobj = {
				count: 0
			}
			// 这是一个计数器组件,身上有个按钮,每当点击按钮,让data中的count值+1
			Vue.component('mycom1', {
				template: '#tmp',

				data: function() {
					// 如果返回对象的话,组件会跟着一起动
					// return dataobj
					return {count:0}
				},
				methods: {
					add() {
						this.count++
					}
				},
			}, )
			var vm = new Vue({
				el: '#app',
				data: {

				},
				methods: {


				}
			});
		</script>
	</body>

</html>

在这里插入图片描述

使用flag标识符结合v-if和v-else切换组件和使用is属性来切换不同的子组件,并添加切换动画

v-if组件切换

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>组件切换</title>
    <script src="vue-2.4.0.js"></script>
</head>

<body>
    <div id="app">
		<a href="" @click.prevent="flag=true">登录</a>
		<a href="" @click.prevent="flag=false">注册</a>
		
		<login v-if="flag"></login>
		<register v-else="flag"></register>
	</div>
    <script>
		
		Vue.component('login',{
			template:'<h3>登录组件</h3>'
		})
		
		Vue.component('register',{
			template:'<h3>注册组件</h3>'
		})
		
        var vm=new Vue({
           el:'#app',
           data:{
			   flag:false
		   },
           methods:{}
        });
    </script>
</body>

</html>

:is属性

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>组件切换方式2</title>
    <script src="vue-2.4.0.js"></script>
</head>

<body>
    <div id="app">
		<a href="" @click.prevent="comName='login'">登录</a>
		<a href="" @click.prevent="comName='register'">注册</a>
		<!-- Vue 提供component,来展示对应名称的组件 -->
		<!-- component 是一个占位符,:is 属性,可以用来指定要展示的组件的名称 -->
		<component :is="comName"></component>
		
		<!-- 总结:当前学习了几个Vue 提供的标签 -->
		<!-- component,template,transition,transitionGroup -->
	</div>
    <script>
		// 创建组件
		Vue.component('login',{template:'<h3>登录组件</h3>'})
		Vue.component('register',{template:'<h3>注册组件</h3>'})
		
		
        var vm=new Vue({
           el:'#app',
           data:{
			   comName:'login'
		   },
           methods:{}
        });
    </script>
</body>

</html>

动画

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>组件切换方式2</title>
	<style type="text/css">
		.v-enter,
		.v-leave-to{
			opacity: 0;
			transform: translateX(150px);
		}
		.v-enter-active,
		.v-leave-active{
			transition: all 0.8s ease;
		}
	</style>
    <script src="vue-2.4.0.js"></script>
</head>

<body>
    <div id="app">
		<a href="" @click.prevent="comName='login'">登录</a>
		<a href="" @click.prevent="comName='register'">注册</a>
		<!-- Vue 提供component,来展示对应名称的组件 -->
		<!-- component 是一个占位符,:is 属性,可以用来指定要展示的组件的名称 -->
		<!-- 通过mode属性,设置组件切换时候的模式 -->
		<transition mode="out-in">
			<component :is="comName"></component>
		</transition>
		
		
		<!-- 总结:当前学习了几个Vue 提供的标签 -->
		<!-- component,template,transition,transitionGroup -->
	</div>
    <script>
		// 创建组件
		Vue.component('login',{template:'<h3>登录组件</h3>'})
		Vue.component('register',{template:'<h3>注册组件</h3>'})
		
		
        var vm=new Vue({
           el:'#app',
           data:{
			   comName:'login'
		   },
           methods:{}
        });
    </script>
</body>

</html>
在这里插入图片描述

父组件向子组件传值

1.组件实例定义方式,注意:一定要使用props属性来定义父组件传递过来的数据
2.使用v-bind或简化指令,将数据传递到子组件中

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>父组件向子组件传值</title>
    <script src="vue-2.4.0.js"></script>
</head>

<body>
    <div id="app">
		<!-- 父组件可以在引用子组件的时候,通过属性绑定(v-bind:)的形式,把需要传递给子组件的数据,以属性绑定的形式,传递到子组件的内部,供子组件使用 -->
		<com1 :parentmsg="msg"></com1>
	</div>
    <script>
	
        var vm=new Vue({
           el:'#app',
           data:{
			   msg:'这是父组件中的数据'
		   },
           methods:{},
		   components:{
			   // 结论:经过演示,发现子组件中,默认无法访问到父组件中的data上的数据和methods中的方法
			   com1:{
				   data(){
					   // 注意:子组件中的data数据,并不是通过父组件传递过来的,而是子组件自身私有的,比如:子组件通过ajax,请求回来的数据,都可以放到data身上
					   // data上的数据,都是可读可写的
					   return {
						   title:'123',
						   conent:'qqq'
					   }
				   },
				   template:'<h1 >这是子组件----{{ parentmsg }}</h1>',
				   // 注意:组件中的所有props 中的数据,都是通过父组件传递给子组件的
				   // props 中的数据,都是只读的,无法重新赋值
				   props:['parentmsg'],//把父组件传递过来的parentmsg属性,先在props数组中,定义一下这样才能使用这个数据
				   methods:{
					   // change(){
						  //  this.parentmsg='被修改了!'
					   // }
				   }
			   }
		   }
        });
    </script>
</body>

</html>

子组件向父组件传值

1.原理:父组件将方法的引用,传递到子组件内部,子组件在内部调用父组件传递过来的方法,同时把要发送给父组件的数据,在调用方法的时候当作参数传递进去
2.父组件将方法的引用传递给子组件,其中getmsg是父组件中methods中定义的方法名称,func是子组件调用床底过来方法时候的方法名称
3.子组件内部通过this.$emit(‘方法名’,要传递的数据)方式,来调用父组件中的方法,同事把数据传递给父组件使用

<!DOCTYPE html>
<html lang="en">

	<head>
		<meta charset="UTF-8">
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<meta http-equiv="X-UA-Compatible" content="ie=edge">
		<title>父组件向子组件传方法</title>
		<script src="vue-2.4.0.js"></script>
	</head>

	<body>
		<div id="app">
			<h2>{{datamsgFormSon}}</h2>
			<!-- 父组件向子组件传递方法,使用的是事件绑定机制:v-on: 当我们定义了一个事件属性之后,那么子组件就能够通过某些方式来调用传递进去的这个方法了 -->
			<com1 @func="show" ></com1>
		</div>
		<template id="tmp1">
			<div id="">
				<h1>这是子组件 ---- {{sonmsg.name}}</h1>
				<input type="button" name="" id="" value="这是子组件的按钮点击触发父组件的方法" @click="myclick" />
			</div>

		</template>
		<script>
			// 定义了一个字面量类型的组件模板对象
			var com1 = {
				template: '#tmp1',  //通过指定了一个Id,表示说,要去加载这个指定Id的template 元素中的内容,当作组件的HTML结构
				data() {
					return {
						sonmsg: {
							name: '小头爸爸',
							age: 35
						}
					}
				},
				methods: {
					myclick() {
						// 当点击子组件的按钮的时候,如何拿到父组件传递过来的func方法
						// emit :触发、调用、发射的意思
						// 第二个变量就是参数
						this.$emit('func', this.sonmsg.name)
					}
				}
			}
			var vm = new Vue({
				el: '#app',
				data: {
					datamsgFormSon: null
				},
				methods: {
					// 可以带参数
					show(data) {
						console.log('调用了父组件身上的show方法 -----'  + data)
						console.log(data)
						this.datamsgFormSon = data
					}
				},
				components: {
					com1
				}
			});
		</script>
	</body>

</html>

评论列表案例

使用this.$refs来获取元素和组件

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>ref获取DOM元素和组件</title>
    <script src="vue-2.4.0.js"></script>
</head>

<body>
    <div id="app">
		<input type="button" name="" id="" value="获取元素" @click="getElement" ref="mybtn" />
		<h3 id="myh3" ref="myh3">哈哈哈,今天天气太好了!</h3>
	<hr >
	<login ref="mylogin"></login>
	</div>
    <script>
		var login = {
			template:'<h1>登录组件</h1>',
			data(){
				return {
					msg:'son Msg'
				}
			},
			methods:{
					
				show(){
					console.log('调用了子组件的方法')
				}
			}
		}
		
        var vm=new Vue({
           el:'#app',
           data:{},
           methods:{
			   getElement(){
				   console.log(document.getElementById('myh3').innerHTML)
				   
				   // ref 是英文单词【reference】值类型和引用类型 referenceError
				   console.log(this.$refs.myh3.innerHTML)
				   console.log(this.$refs.mylogin.msg)
				   console.log(this.$refs.mylogin.msg)
				   this.$refs.mylogin.show()
			   }
		   },
		   components:{
			   login
		   }
        });
    </script>
</body>

</html>

评论列表

<!DOCTYPE html>
<html lang="en">

	<head>
		<meta charset="UTF-8">
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<meta http-equiv="X-UA-Compatible" content="ie=edge">
		<title>评论列表</title>
		<script src="vue-2.4.0.js"></script>
	</head>
	<link rel="stylesheet" type="text/css" href="bootstrap-3.3.7.css" />

	<body>
		<div id="app">
			<login @func='loadComments'> </login>
			<ul class="list-group">
				<li class="list-group-item" v-for="item in list" :key="item.id">
					<span id="" class="badge">评论人:{{item.user}}
					</span>
					{{item.content}}
				</li>
			</ul>
		</div>
		<template id="tmp">
			<div>
				<div class="form-group">
					<label>评论人:</label>
					<input type="text" class="form-control" v-model="user">
				</div>
				<div class="form-group">
					<label>评论内容:</label>
					<textarea name="" id="input" class="form-control" rows="3" required="required" v-model="content" @keyup.enter="postComment"></textarea>
				</div>
				<div class="form-group">
					<input type="button" name="" id="" value="发表评论" class="btn btn-primary" @click="postComment" />
				</div>
			</div>
		</template>
		<script>
			var login = {
				template: '#tmp',
				data() {
					return {
						user: '',
						content: ''
					}
				},
				methods: {
					// 发表评论的方法
					// 分析:发表评论的业务逻辑
					// 1.评论数据存到哪里去??? 存放到 localstorage 中 localstorage 中localstorage.setItem('cmts','')
					// 2.先组织出一个最新的评论数据对象
					// 3.想办法,把第二步中,得到的评论对象,保存到localstorage中
					// 3.1 localstorage 只支持存放字符串数据,要先调用JSON.stringify
					// 3.2 在保存最新的评论数据之前,要先从localstorage获取到之前的评论数据(string),转换为一个数组对象,然后把最新的评论push到这个数组
					// 3.3 如果获取到的localstorage中的评论字符串为空不存在,则可以返回一个[] 让JSON.parse去转换
					// 3.4 把最新的评论列表数组,再次调用JSON.stringify转为数组字符串,然后调用localstorage.setItem()
					postComment() {
						var comment = {
							id: Date.now(),
							user: this.user,
							content: this.content
						}
						// 从localstorage 中获取所有的评论
						var list = JSON.parse(localStorage.getItem('cmts1') || '[]')
						list.unshift(comment)
						// 重新保存最新的评论数据
						localStorage.setItem('cmts1', JSON.stringify(list))
						this.user = this.content = ''

						// this.loadComments()   
						this.$emit('func')
					}

				}
			}

			var vm = new Vue({
				el: '#app',
				data: {
					list: [{
							id: Date.now(),
							user: '李白',
							content: '黄河之水天上来'
						},
						{
							id: Date.now(),
							user: '李清照',
							content: '至今思项羽'
						},
						{
							id: Date.now(),
							user: '屈原',
							content: '虽九死其犹为悔'
						},
					]
				},
				methods: {
					loadComments() { // 从本地的localstorage中,加载评论列表
						var list = JSON.parse(localStorage.getItem('cmts1') || '[]')
						this.list = list
					}
				},

				components: {
					login
				},
				beforeCreate() {
					//注意:这里不能调用loadcomments方法,因为在执行这个钩子函数的时候,data和methods都还没有被初始化好
				},
				created() {
					this.loadComments()
				}
			});
		</script>
	</body>

</html>

在这里插入图片描述
在这里插入图片描述

这篇文章有一个评论

发表评论