vue 框架学习(5) 组件化开发 和 父子组件传值

第六节:Vue组件化开发(1)-什么是组件

一、什么是组件

1.1 单个理解

最简单的理解,组件也相当于一个小型的Vue实例,组件也可以有实例的各种属性。

组件是一个完整的单位个体,可以有js可以有css和html。(现在写的是没有包含css和js)。

1.2 整体理解

开发过html的人都知道,其实我们界面是由一个个div的布局来显示出来,每一个div里都有对应的展示内容,如果我们把这一个个div想象成一个整体,整体中又可以嵌套一个整体,最后我们界面就会变成一个个小模块组成。

Vue组件开发就是这个模式,先定义一个个组件(相当于一个div),组件可以嵌套,然后组成一个整体

如下图: 通常一个应用会以一棵嵌套的组件树的形式来组织:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vJk7T308-1612834014926)(vue笔记2_files/1.jpg)]

1.3 组件的好处

可复用

低耦合

二、Vue组件初次使用

2.1 创建组件的第一种方式:

使用Vue.component创建一个组件

  • 第一个参数是组件的名称(就是我们后续使用的元素标识)
  • 第二个参数是对象,里面有很多参数,现在只说一个template(模板),就是我们存放展示内容的地方
Vue.component('component1',{
	template::`
	<div> 
	<h1>hello</h1>
	<h1>我的第一个组件</h1>
	</div>
	`
});

2.2 创建组件的第二种方式:

在Vue实例里注册,先定义好对象,然后在实例的components属性上把组件注册

//创建组件2 先定义好对象,然后在实例的components属性上把组件注册
const componentA ={
	template:`
	<div><h2>我的第二个组件 Hi </h2> </div>
	`
}
const app = new Vue({
	el:"#app",
	data: {
		number: 0
	},
	components:{
		'compontent2':componentA
	}
})

2.3 使用组件

1)怎么使用Vue的创建组件?

在创建组件的时候,我们都是有定义一个标志,如果是使用Vue.component创建就是第一个参数,如果是在components注册就是对象的名称

2)使用(直接用标识名称来使用组件)

组件的使用必须在Vue实例的div里,超出的实例,vue无法管理就无法使用这个组件了

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>hello Vue</title>
	</head>
	<body>
		<div id="app">
			<!--直接用标识名称来使用组件-->
			<component1></component1>
			<!--组件复用-->
			<component1></component1>
			<component1></component1>
			<component2></component2>
		</div>
	</body>
	<script src="./vue.js"></script>
	<script>
	        // 创建组件1
			Vue.component('component1',{
				template:`
				<div> 
				<h1>hello</h1>
				<h1>我的第一个组件</h1>
				</div>
				`
			});
			//创建组件2 先定义好对象,然后在实例的components属性上把组件注册
			const component2 ={
				template:`
				<div> <h2>我的第二个组件 Hi </h2> </div>
				`
			}
			const app = new Vue({
				el:"#app",
				components:{
					'component2':component2
				}
			})
			
	</script>
</html>

三、Vue组件模板的分离写法

3.1 为什么要用使用分离写法?

我们知道组件的展示内容是在属性template定义好的,然后会发现div的内容都直接在对象里面写,如果简单的内容还是可以的,但是实际的开发,肯定是比较复杂是功能,如果直接写在对象里就有点不好维护,也不好理解代码。如果把这个template对应的div放出来,那我们组件对象就好维护很好

3.2 怎么分离元素

有一个元素标签template就可以办到分离写法,在定义好,定义好id,然后在对象里用’#id’就可以了

<template id="component3">
	<div>
		<h2>hhhhhhhhhhh</h2>
	</div>
</template>

<!-- 组件的对象使用(’#id’)  -->

Vue.component("component3",{
	template: '#component3'
});

四、Vue-全局组件和局部组件

4.1 什么是全局组件?

全局组件:只要是用Vue.component 来创建的组件都是全局注册的 。也就是说它们在注册之后可以用在任何新创建的 Vue 根实例 (new Vue) 的模板中,局部组件和子组件都能使用。
比如你实例了两个new Vue(),这个全局组件就可以在这两个实例上都可以使用。(但是我们一般不会创建两个实例)
下面代码说明,我创建了全局组件,在两个实例app和app1都可以使用

<body>
<div id="app"  >
    <component1></component1>
</div>
<div id="app1" >
    <component1></component1>
</div>

<template id="component1">
    <div style="background: darkcyan">
        <h2>我的第一个组件</h2>
    </div>
</template>
</body>
<script src="../css/vue.js"></script>
<script>
    Vue.component('component1', {
        template: '#component1'
    });
    const app = new Vue({
        el: '#app'
    })
    const app1 = new Vue({
        el: '#app1'
    })
</script>

4.2 什么是局部组件?

局部组件: 在实例的属性components或者是组件里的属性components上注册组件,叫局部组件局部注册的组件在其子组件中不可用,如果要使用需要多重嵌套。

用下面的代码说明:在实例中只用component2组件,不能使用component1,因为component1没有在实例上注册

<body>
<div id="app"  >
    <component1></component1>
    <!-- component2使用会报错 -->
    <component2></component2>
</div>
<template id="component1">
    <div style="background: darkcyan">
        <h2>我的第一个组件</h2>
    </div>
</template>
<template id="component2">
    <div style="background: aqua">
        <component1></component1>
        <h2>我的第二个组件</h2>
    </div>
</template>

</body>
<script src="./vue.js"></script>
<script>
	const component1 = {
        template: '#component1'
    }
    const component2 = {
        template: '#component2',
        components: {
            'component1': component1
        }
    }
    const app = new Vue({
        el: '#app',
        components: {
            'component2': component2
	       <!--'component1': component1  -->
        }
    })
</script>

demo:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>hello vue</title>
</head>
<body>
<div id="app"  >
    <component1></component1>
    <component2></component2>
</div>

<div id="app1" >
    <component1></component1>
</div>

<template id="component1">
    <div style="background: darkcyan">
        <h2>我的第一个组件</h2>
        <h2>你们好</h2>
    </div>
</template>

<template id="component2">
    
    <div style="background: aqua">
        <component1></component1>
        <h2>我的第二个组件</h2>
    </div>
</template>

</body>
<script src="../css/vue.js"></script>
<script>
    /**
     * 全局组件:只要是用 Vue.component 来创建的组件都是全局注册的。也就是说它们在注册之后可以用在任何新创建的 Vue 根实例 (new Vue) 的模板中,局部组件和子组件都能使用
     * 比如你实例了两个new Vue();这个全局组件就可以在这两个实例上都可以使用。(但是我们一般不会创建两个实例)
     * */
    Vue.component('component1', {
        template: '#component1'
    });

    /**
     * 局部组件:在实例的属性components或者是组件里的属性components上注册组件,叫局部组件,局部注册的组件在其子组件中不可用,如果要使用需要多重嵌套
     * @type {
   
   {template: string}}
     */
    const component2 = {
        template: '#component2'
    }
    const app = new Vue({
        el: '#app',
        components: {
            'component2': component2
        }
    })

    const app1 = new Vue({
        el: '#app1',
    })

</script>
</html>

五、Vue-父组件和子组件

5.1 什么是父子组件?

其实就是组件里通过components再嵌套注册组件,嵌套注册组件的就是子组件,被嵌套就是父组件

如图,红色区域就是父组件,嵌套在里面的蓝色区域就是子组件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QZCwS4kA-1612834014930)(vue笔记2_files/2.jpg)]

注意:全局组件不存在父组件和子组件的,因为全局组件在实例里的任何地方都可以使用

5.2 父子组件体现在代码上的结构

看下面例子的代码

Vue实例就是一个最大的父组件,component1注册在实例上,那component1就是Vue实例的子组件

component2注册在component1组件上,那component2就是component1组件的子组件

<div id="app">
    <component1></component1>
</div>
<template id="component1">
    <div>
        <h2>我的第一个组件</h2>
        <component2></component2>
    </div>
</template>
<template id="component2">
    <div>
        <h2>我的第二个组件</h2>
    </div>
</template>
</body>
<script src="../css/vue.js"></script>
<script>
    const component1 = {
        template: '#component1',
        components: {
            'component2': {
                template: "#component2"
            }
        }
    }
    const app = new Vue({
        el: '#app',
        components: {
            'component1': component1
        }
    })
</script>

六、Vue组件数据

6.1 组件可以直接访问Vue实例的数据吗?比如直接用{ {}}

答案是不能。

组件是一个单独功能模块的封装(相当于一个小的Vue实例),就是这个模块有属于自己的HTML模板,也有自己属性数据data。
我们看看下面的代码,我们在子组件直接用{ {mes}}来使用父组件的data属性的值mes

<body>
<div id="app">
    <component1></component1>
</div>
<template id="component1">
    <div>
        <h2>{
   
   {mes}}</h2>
    </div>
</template>
</body>
<script src="./vue.js"></script>
<script>
    const component1 = {
        template: '#component1'
    }
    const app = new Vue({
        el: '#app',
        data:{
          mes: "实例数据"
        },
        components: {
            'component1': component1
        }
    })
</script>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2MDeB1Lb-1612834014933)(vue笔记2_files/3.jpg)]

6.2 组件数据存放

组件对象也有一个data属性,但是data属性必须是一个函数,然后这个返回的对象,对象内部保证这数据

<body>
<div id="app">
    <component1></component1>
</div>
<template id="component1">
    <div>
        <h2>{
   
   {mes}}</h2>
    </div>
</template>
</body>
<script src="./vue.js"></script>
<script>
    const component1 = {
        template: '#component1',
        data(){
            return{mes: "实例数据"}
        },
    }
    const app = new Vue({
        el: '#app',
        components: {
            'component1': component1
        }
    })
</script>

6.3 Vue组件中的data为什么是函数?

为什么组件的data是一个函数,官网说: 一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝

我们都是知道,对象一旦创建就会指定一个地址,每个人去用这个对象的时候,都是修改对象的属性值,地址是不是改变了,然后回想一下,组件的使用很多时候都是要复用的,你复用的时候,都会想着每个组件的数据都是单独维护的,不要相互影响。如果对象都是只是创建一次,那就会出问题了,现在有一个组件使用了两次,data内存地址都是一个,那一个组件修改了data,另一个组件的值也会跟着改变,这个是我们最不想看到的情况。那data是一个函数的话就不一样了,函数每次返回的对象都是一个新对象,这样就保持了每个组件的对象都不想相互影响

一句话:就是为了保证每个组件的data对象都是相互独立

七、Vue组件通信-父组件给子组件传递参数

之前我们说,组件不能直接使用Vue实例的数据,但是实际开发过程,组件使用Vue实例的数据很正常

7.1 组件要怎样才能使用父组件的数据呢?

通过 Prop 向子组件传递数据

7.2 Prop 使用

1)props属性的值为数组

定义

在组件对象里使用props属性,然后直接定义数组,数组的对应的值就是获取的传参的对象。

 const component1 = {
	template: "#component1",
	props: ['propsMessage','propsmessage1'],
}

使用

在使用组件的时候,我只要把这些定义好数组的值,当成是组件的属性值就可以直接传递参数了。(使用v-bind可以使用父组件的data数据)

 <!-- 使用v-bind可以使用父组件的data数据 -->
 <component1 v-bind:props-message=message propsmessage1='参数1'></component1>

2)props属性的值为对象

对象的用处:允许配置高级选项,如类型检测、自定义验证和设置默认值

你可以基于对象的语法使用以下选项:

对象属性值 说明
type 可以是下列原生构造函数中的一种:String、Number、Boolean、Array、Object、Date、Function、Symbol、任何自定义构造函数、或上述内容组成的数组。会检查一个 prop 是否是给定的类型,否则抛出警告。
default:any 为该 prop 指定一个默认值。如果该 prop 没有被传入,则换做用这个值。对象或数组的默认值必须从一个工厂函数返回
required:Boolean 定义该 prop 是否是必填项。在非生产环境中,如果这个值为 truthy 且该 prop 没有被传入的,则一个控制台警告将会被抛出。
validator:Function 自定义验证函数会将该 prop 的值作为唯一的参数代入。在非生产环境下,如果该函数返回一个 falsy 的值 (也就是验证失败),一个控制台警告将会被抛出

定义

和组数差不多,props属性是最大的一层对象,属性值是传递参数对象,然后可以对传递参数进行各种个性化设置

示例:

<body>
<div id="app">
    <component1 v-bind:props-message=message height="哈哈" age= -1></component1>
    <!--如果不使用v-bind会识别不了data的数据-->
   <component1 props-message=message></component1>
</div>
<template id="component1">
    <div>
        <h2>{
   
   {propsMessage}}</h2>
        <h2>{
   
   {height}}</h2>
        <h2>{
   
   {age}}</h2>
    </div>
</template>
</body>
<script src="./vue.js"></script>
<script>
    const component1 = {
        template: "#component1",
        props: {
            // 检测类型
            propsMessage: String,
            height: String,
            // 检测类型 + 其他验证
            age: {
                type: Number,
                default: 0,
                required: true,
                validator: function (value) {
                    return value >= 0
                }
            }
        }
    }
    const app = new Vue({
        el: '#app',
        data: {
            message: "你好"
        },
        components: {
            'component1': component1
        }
    })
</script>

八、Vue组件通信-子组件向父组件的自定义事件

1) 怎样子组件向父组件传递数据

子组件给父组件传递数据的时候,就要使用自定义事件来实现

自定义事件的流程:

  • 在子组件中,通过$emit来触发事件

  • 在父组件,通过v-on来监听子组件事件

<!--子组件-->
<template id="component1">
    <div>
        <button @click="but">子组件按钮触发父组件事件</button>
        <button @click="but1">子组件按钮触发父组件事件并带参数</button>
    </div>
</template>

子组件的对象定义( 注意这个驼峰标识不能用,需要使用 kebab-case)

const component1 = {
        template: "#component1",
        methods: {
            but() {
                console.log("子组件按钮被触发了");
                //注意这个驼峰标识不能用,需要使用 kebab-case
                this.$emit('cpn-but');
            },
            but1() {
                console.log("子组件按钮并带参数被触发了");
                //注意这个驼峰标识不能用,需要使用 kebab-case
                //子组件按钮触发父组件事件并带参数,就在this.$emit加多一个参数对象
                this.$emit('cpn-but1', 'hhhh');
            }
        }
    }

2)父组件定义

父组件在使用子组件的时候,使用v-on指令,属性值就是子组件定义好的this.$emit(‘cpn-but’)的名称

<!--父组件-->
<div id="app">
    <component1 @cpn-but="cpnBut" @cpn-but1="cpnBut1"></component1>
</div>

然后在父组件的methods写上触发的方法就是可以接受子组件触发

const app = new Vue({
        el: '#app',
        data: {
            message: "你好"
        },
        components: {
            'component1': component1
        },
        methods: {
            cpnBut() {
                console.log("父组件的方法被触发了");
            },
            cpnBut1(val) {
                console.log("父组件事件并带参数被触发了");
                console.log("参数:" + val);
            }
        }
    })

示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>hello vue</title>
</head>
<body>
<!--父组件-->
<div id="app">
    <component1 @cpn-but="cpnBut" @cpn-but1="cpnBut1"></component1>
</div>

<!--子组件-->
<template id="component1">
    <div>
        <button @click="but">子组件按钮触发父组件事件</button>
        <button @click="but1">子组件按钮触发父组件事件并带参数</button>
    </div>
</template>

</body>
<script src="../css/vue.js"></script>
<script>
    const component1 = {
        template: "#component1",
        methods: {
            but() {
                console.log("子组件按钮被触发了");
                //注意这个驼峰标识不能用,需要使用 kebab-case
                this.$emit('cpn-but');
            },
            but1() {
                console.log("子组件按钮触并带参数被触发了");
                //注意这个驼峰标识不能用,需要使用 kebab-case
                //子组件按钮触发父组件事件并带参数,就在this.$emit加多一个参数对象
                this.$emit('cpn-but1', 'hhhh');
            }
        }
    }

    const app = new Vue({
        el: '#app',
        data: {
            message: "你好"
        },
        components: {
            'component1': component1
        },
        methods: {
            cpnBut() {
                console.log("父组件的方法被触发了");
            },
            cpnBut1(val) {
                console.log("父组件事件并带参数被触发了");
                console.log("参数:" + val);
            }
        }
    })

</script>
</html>

参考:https://blog.csdn.net/qq_30442207/article/details/108813033

猜你喜欢

转载自blog.csdn.net/weixin_44433499/article/details/113766202
今日推荐