首页 > 技术文章 > 四、Vue组件

binyuanxiang 2019-12-19 22:04 原文

一、组件简介

1. 组件的概念

	组件是html、css与js的集合体。给该集合体命名后,可以通过名字对组件进行复用。
	
	
2. 组件分类
	
	a. 根组件
	
		用new Vue()生成的组件。
	
	b. 局部组件
	
		组件名 = {}, ‘{}’内部采用vue语法。
	
	c. 全局组件
	
		Vue.component('组件名',{}), ‘{}’内部采用vue语法。
	
	
3. 组件的特点

	a. 组件都有管理组件html页面结果的template实例成员,template中有且只有一个跟标签。
	
	b. 根组件可以不明确template,template默认采用挂载点页面结构;如果设置的template,挂载点内部的内容无效,因为会被替换。
	
	c. 根组件都是作为最顶层父组件,局部与全局组件作为子组件,也可以成为其他局部与全局组件的父组件。
	
	d. 子组件的数据需要隔离(数据组件化,每一个组件拥有自己数据的独立名称空间)
	
	e. 局部组件必须注册后才能使用,全局组件不需要注册,提倡使用局部组件。
	
	f. 组件中出现的所有变量(模板中、逻辑中),由该组件自己提供管理。
	
	g. 局部全局和根组件都是一个vue实例,一个实例对应一套html、css、js结构,所以实例就是组件

二、子组件

1. 局部组件

	a. 声明组件
		
		let localTag = {
		    template: `
		    <div class="box" @click="fn">
		        <img src="img/001.jpg" alt="">
		        <h2>美女</h2>
		    </div>
		    `,
		
		    methods: {
		        fn() {
		            console.log(this)
		        }
		    }
		};
		
	b. 注册组件
	
		new Vue({
		    el: '#app',
		    data: {},
		    components: {  // 注册组件
		        localTag,
		    }
		})
		
		
	c. 渲染组件
	
		<div id="app">
		        <local-tag></local-tag>
		</div>
		
		
2. 全局组件

	a. 声明组件
	
		Vue.component('global-tag', {
		    template: `
		    <div class="box" @click="fn">
		        <img src="img/002.jpg" alt="">
		        <h2>大长腿</h2>
		    </div>
		    `,
		    methods: {
		        fn() {
		            console.log(this)
		        }
		    }
		});
		
		
	b. 渲染组件
	
		<div id="app">
			<global-tag></global-tag>
		</div>

三、组件化

1. 概念

	局部或全局取件,一个组件可能会被复用多次,此时每个组件都应该有自己独立的变量名称空间。

2. 实现方法

	将组件中的数据,作为方法的返回值(方法执行后会产生一个局部作用域)

3. 代码

	let localTag = {
	    template: `
	    <div class="box" @click="fn">
	        <img src="img/001.jpg" alt="">
	        <h2>点击了图片{{ count }}下</h2>
	    </div>
	    `,
	    data() {  
	        return {
	            count: 0,
	        }
	    }, 
	    methods: {
	        fn() {
	            console.log(this);
	            this.count++;
	        }
	    }
	};

四、组件传参:父传子

1. 传参方法
	
	a. 定义要传的对象
	
		let dogs = [
		    {
		        name: '二哈1号',
		        img: 'img/100.jpg',
		    },
		];
		
	
	b. 子组件会在父组件中渲染,渲染时,将父组件的变量绑定给子组件的自定义属性,将可以将变量值传递给子组件
	
		<local-tag v-for="dog in dogs" :dog="dog" def="12345" :xyz="dog.name"></local-tag>
		
	
	c. 子组件可以通过props自定义组件属性(采用反射机制,需要填写字符串,但是使用时可以直接作为变量)
	
		let localTag = {
		    props: ['dog', 'def', 'xyz'],
		
		    template: `
		    <div class="box" @click="fn">
		        <img :src="dog.img" alt="">
		        <h2>捶{{ dog.name }}{{ count}}下</h2>
		        <!--<h3>{{ abc }}</h3>-->
		        <!--<h3>{{ def }}</h3>-->
		        <!--<h3>{{ xyz }}</h3>-->
		    </div>
		    `,
		    data() {
		        return {
		            count: 0,
		        }
		    },
		    methods: {
		        fn() {
		            console.log(this.dog);
		            this.count++;
		        }
		    }
		};
	
	
	
2. 点击图片示例

	<head>
	    <meta charset="UTF-8">
	    <title>父传子</title>
	    <style>
	        body, h2 {
	            margin: 0;
	        }
	
	        .wrap {
	            width: 880px;
	            margin: 0 auto;
	        }
	
	        .wrap:after {
	            content: '';
	            display: block;
	            clear: both;
	        }
	
	        .box {
	            width: 200px;
	            border-radius: 10px;
	            overflow: hidden;
	            background-color: #eee;
	            float: left;
	            margin: 10px;
	        }
	
	        .box img {
	            width: 200px;
	            height: 240px;
	        }
	
	        .box h2 {
	            text-align: center;
	            font-weight: normal;
	            font-size: 20px;
	        }
	    </style>
	</head>
	<body>
	<div id="app">
	    <div class="wrap">
	        <local-tag v-for="dog in dogs" :dog="dog" def="12345" :xyz="dog.name"></local-tag>
	    </div>
	</div>
	
	</body>
	<script src="js/vue.js"></script>
	<script>
	    let dogs = [
	        {
	            name: '二哈1号',
	            img: 'img/100.jpg',
	        },
	        {
	            name: '二哈2号',
	            img: 'img/200.jpg',
	        },
	        {
	            name: '二哈3号',
	            img: 'img/300.jpg',
	        },
	        {
	            name: '二哈4号',
	            img: 'img/400.jpg',
	        },
	        {
	            name: '二哈1号',
	            img: 'img/100.jpg',
	        },
	        {
	            name: '二哈2号',
	            img: 'img/200.jpg',
	        },
	        {
	            name: '二哈3号',
	            img: 'img/300.jpg',
	        },
	        {
	            name: '二哈4号',
	            img: 'img/400.jpg',
	        }
	    ];
	    
	    let localTag = {
	        props: ['dog', 'def', 'xyz'],
	
	        template: `
	        <div class="box" @click="fn">
	            <img :src="dog.img" alt="">
	            <h2>捶{{ dog.name }}{{ count}}下</h2>
	            <!--<h3>{{ abc }}</h3>-->
	            <!--<h3>{{ def }}</h3>-->
	            <!--<h3>{{ xyz }}</h3>-->
	        </div>
	        `,
	        data() {
	            return {
	                count: 0,
	            }
	        },
	        methods: {
	            fn() {
	                console.log(this.dog);
	                this.count++;
	            }
	        }
	    };
	
	    new Vue({
	        el: '#app',
	        data: {
	            dogs,
	        },
	        components: {
	            localTag,
	        }
	    });
	</script>
	</html>

五、组件传参:子传父

1. 传参方法

	a. 自定义组件标签的事件,该事件方法由父组件来实现。
	
		<tag @action="actionFn"></tag>
		<hr>
		<tag2 @h1a="aFn1" @h3a="aFn3"></tag2>
	
	b. 子组件触发自定义事件:this.$emit('自定义事件名',触发事件回调的参数们)
	
		let tag = {
		    template: `
		    <div>
		        <input type="text" v-model="t1">
		        <input type="text" v-model="t2">
		        <button @click="changeTitle">修改标题</button>
		    </div>
		    `,
		    data() {
		        return {
		            t1: '',
		            t2: '',
		        }
		    },
		    methods: {
		        changeTitle() {
		            if (this.t1 && this.t2) {
		                this.$emit('action', this.t1, this.t2);
		                this.t1 = '';
		                this.t2 = '';
		            }
		        }
		    }
		};
		
	
	c. 子组件触发自定义事件,携带出子组件的内容,在父组件中实现自定义事件的方法。
	
		new Vue({
		    el: '#app',
		    data: {
		        h1: '主标题',
		        h3: '子标题'
		    },
		    components: {
		        tag,
		        tag2,
		    },
		    methods: {
		        actionFn(a, b, c) {
		            // console.log('触发了', a, b, c);
		            this.h1 = a;
		            this.h3 = b;
		        },
		        aFn1(a) {
		            if (!a) {
		                this.h1 = '主标题';
		                return;
		            }
		            this.h1 = a;
		        },
		        aFn3(a) {
		            if (!a) {
		                this.h3 = '子标题';
		                return;
		            }
		            this.h3 = a;
		        },
		    }
		})
		
	
2. 实时修改标签示例

	<body>
	    <div id="app">
	        <h1>{{ h1 }}</h1>
	        <h3>{{ h3 }}</h3>
	
	
	        <!--
	        -->
	        <tag @action="actionFn"></tag>
	        <hr>
	        <tag2 @h1a="aFn1" @h3a="aFn3"></tag2>
	    </div>
	</body>
	<script src="js/vue.js"></script>
	<script>
	    let tag = {
	        template: `
	        <div>
	            <input type="text" v-model="t1">
	            <input type="text" v-model="t2">
	            <button @click="changeTitle">修改标题</button>
	        </div>
	        `,
	        data() {
	            return {
	                t1: '',
	                t2: '',
	            }
	        },
	        methods: {
	            changeTitle() {
	                if (this.t1 && this.t2) {
	                    // console.log(this.t1, this.t2);
	                    this.$emit('action', this.t1, this.t2);
	                    this.t1 = '';
	                    this.t2 = '';
	                }
	            }
	        }
	    };
	
	
	    let tag2 = {
	        template: `
	        <div>
	            主标题内容:<input type="text" v-model="t1" @input="t1Fn">
	            子标题内容:<input type="text" v-model="t2">
	        </div>
	        `,
	        data() {
	            return {
	                t1: '',
	                t2: '',
	            }
	        },
	        methods: {
	            t1Fn() {
	                this.$emit('h1a', this.t1);
	            }
	        },
	        watch: {
	            t2 () {
	                this.$emit('h3a', this.t2);
	            }
	        }
	    };
	
	    new Vue({
	        el: '#app',
	        data: {
	            h1: '主标题',
	            h3: '子标题'
	        },
	        components: {
	            tag,
	            tag2,
	        },
	        methods: {
	            actionFn(a, b) {
	                this.h1 = a;
	                this.h3 = b;
	            },
	            aFn1(a) {
	                if (!a) {
	                    this.h1 = '主标题';
	                    return;
	                }
	                this.h1 = a;
	            },
	            aFn3(a) {
	                if (!a) {
	                    this.h3 = '子标题';
	                    return;
	                }
	                this.h3 = a;
	            },
	        }
	    })

推荐阅读