vue基础入门(3)

3.组件基础

3.1.什么是组件?

3.1.1.理解组件

前端组件化开发是目前非常流行的方式,什么是前端组件化开发呢?就是将页面的某一部分独立出来,将这一部分的数据、视图、以及一些控制逻辑封装到一个组件内部,暴露一些开箱即用的函数或者属性供外部组件调用。这种组织代码的开发方式我们称为组件化开发。通俗的说,我们需要把一个页面拆分成若干的小单元,每个小单元就是一个小组件,例如,一个网页,我们可以做如下拆分

组件开发的好处就是可以复用代码,下面是组件库举例

点击查看,Element UI

3.1.2.vue中的组件

在vue中,所有的 Vue 组件同时也都是 Vue 的实例,所以可接受相同的选项对象 (除了一些根级特有的选项) 并提供相同的生命周期钩子。Vue组件带有一个名字,在根实例中,组件被定义为元素使用,下面我们来定义一个button计数器组件

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<div id="app">
    <button-counter></button-counter>
    <button-counter></button-counter>
    <button-counter></button-counter>
    <button-counter></button-counter>
    <button-counter></button-counter>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>

    Vue.component('button-counter',{
        data(){
           return {
               num: 0
           }
        },
        methods:{
            fn(){
               this.num++
            }
        },
        template:'<button @click="fn">点击我,自己加1:{{num}}</button>'
    });
    let vm = new Vue({
        el: '#app'
    });
</script>
</body>
</html>

注意:组件中的data必须写成函数的形式,如果不写成函数的形式,组件间数据改变会相互影响

3.1.3.组件定义实例

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        body {
            margin: 0;
        }
    </style>
</head>
<body>
<div id="app">
    <header-component></header-component>
    <main-component></main-component>
    <footer-component></footer-component>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
    //头部组件
    Vue.component('header-component', {
        template: "<div :style='styles'>这里是头部区域</div>",
        computed: {
            styles() {
                return {
                    width: '100%',
                    height: '100px',
                    backgroundColor: 'black',
                    color: 'white',
                    textAlign: 'center',
                    lineHeight: '100px',
                    fontSize: '30px'
                }
            }
        }
    });
    Vue.component('main-component', {
        template: `<div :style="styles">
                    <mainleft-component></mainleft-component>
                    <mainright-component></mainright-component>
                    </div>`,
        computed: {
            styles() {
                return {
                    width: '100%',
                    height: '500px',
                    backgroundColor: 'orangered',
                    paddingTop: '50px'
                }
            }
        }
    });
    Vue.component('mainleft-component', {
        template: '<div :style="styles"></div>',
        computed: {
            styles() {
                return {
                    width: '35%',
                    height: '400px',
                    backgroundColor: 'green',
                    float: 'left'
                }
            }
        }
    });
    Vue.component('mainright-component', {
        template: '<div :style="styles"></div>',
        computed: {
            styles() {
                return {
                    width: '60%',
                    height: '400px',
                    backgroundColor: 'blue',
                    float: 'right'
                }
            }
        }
    });
    Vue.component('footer-component', {
        template: '<div :style="styles">这里是底部区域</div>',
        computed: {
            styles() {
                return {
                    width: '100%',
                    height: '150px',
                    backgroundColor: 'black',
                    color: 'white',
                    textAlign: 'center',
                    lineHeight: '150px',
                    fontSize: '30px'
                }
            }
        }
    });
    let vm = new Vue({
        el: '#app'
    });
</script>
</body>
</html>

3.1.4.组件的父子关系

3.2.父组件向子组件传数据

组件有自己的作用域,并且相互之间是相互独立的,这样就涉及到组件间的通信问题,在子组件中是不能直接使用父组件中的数据的,要在子组件中使用父组件的数据,可以在子组件注册的时候用props选项来声明一个自定义属性,然后在使用组件的时候,通过这个自定义属性来绑定数据

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<div id="app">
    <button @click="showLogin">登录</button>
    <button @click="showRegister">注册</button>
    <template v-if="flagLogin">
        <dialog-component :title="loginTitle"></dialog-component>
    </template>
    <template v-if="flagRegister">
        <dialog-component :title="registerTitle"></dialog-component>
    </template>

</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
    Vue.component('dialog-component', {
        template: '<div :style="box"><div :style="boxTitle">{{title}}</div></div>',
        computed: {
            box() {
                return {
                    width: '300px',
                    height: '300px',
                    border: '1px solid black'
                }
            },
            boxTitle() {
                return {
                    backgroundColor: 'green',
                    textAlign: 'center',
                    height: '30px',
                    lineHeight: '30px',
                    color: 'white'
                }
            }
        },
        props:['title']
    });
    let vm = new Vue({
        el: '#app',
        data: {
            flagLogin: false,
            flagRegister: false,
            loginTitle: '登录',
            registerTitle: '注册'
        },
        methods: {
            showLogin() {
                this.flagLogin = true
            },
            showRegister(){
                this.flagRegister = true
            }
        }
    });
</script>
</body>
</html>

实例2: 新闻列表渲染

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<div id="app">
    <news-component :newsdata="newsdata"  :newstype="newstype"></news-component>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
    Vue.component('news-component', {
        template: `<div :style="wrap">
                        <div :style="wrapTitle">{{newstype}}</div>
                        <div :style="content">
                            <ul v-for="item in newsdata">
                                 <li>{{item.title}}</li>
                            </ul>
                        </div>
                    </div>`,
        computed: {
            wrap() {
                return {
                    width: '300px',
                    height: '400px',
                    border: '1px solid black',

                }
            },
            wrapTitle() {
                return {
                    padding: '15px',
                    width: '100%',
                    borderBottom: '1px solid black',
                    boxSizing: 'border-box'
                }
            },
            content(){
                return {
                    padding: '10px'
                }
            }
        },
        props:['newsdata', 'newstype']
    });
    let vm = new Vue({
        el: '#app',
        data: {
            newstype: '国内新闻',
            newsdata: [
                {'title': '国家药监局:武汉生物百白破疫苗不合格属偶发'},
                {'title': '下月起 这部分人群的抚恤补助标准将再次提高'},
                {'title': '85岁老人40万买保健品 身无分文流落街头称继续买'}
            ]

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

进一步拆分组件

Vue.component('news-component', {
        template: `<div :style="wrap">
                        <div :style="wrapTitle">{{newstype}}</div>
                        <div :style="content">
                            <news-list :news="newsdata"></news-list>
                        </div>
                    </div>`,
        computed: {
            wrap() {
                return {
                    width: '300px',
                    height: '400px',
                    border: '1px solid black',

                }
            },
            wrapTitle() {
                return {
                    padding: '15px',
                    width: '100%',
                    borderBottom: '1px solid black',
                    boxSizing: 'border-box'
                }
            },
            content() {
                return {
                    padding: '10px'
                }
            }
        },
        props: ['newsdata', 'newstype']
    });
    Vue.component('news-list', {
        template: `<ul>
                        <template v-for="item in news">
                            <li>{{item.title}}</li>
                        </template>
                   </ul>`,
        props:['news']
    });
    let vm = new Vue({
        el: '#app',
        data: {
            newstype: '国内新闻',
            newsdata: [
                {'title': '国家药监局:武汉生物百白破疫苗不合格属偶发'},
                {'title': '下月起 这部分人群的抚恤补助标准将再次提高'},
                {'title': '85岁老人40万买保健品 身无分文流落街头称继续买'}
            ]

        }
    });

3.3.子组件向父组件传数据

3.3.1.自定义事件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app"><button-component v-on:myevent="sayhi"></button-component></div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
    Vue.component('button-component', {
        template: `<button @click="$emit('myevent', 'nodeing')">点击</button>`
    });
    new Vue({
        el: '#app',
        methods: {
            sayhi(name){
                alert('hi,' + name)
            }
        }
    })
</script>
</body>
</html>

注意: v-on 事件监听器在 DOM 模板中会被自动转换为全小写 (因为 HTML 是大小写不敏感的),因此,在定义事件名字的时候就不要用大写了,例如: myEvent,如果定义的名字为myEvent,在绑定事件的时候,v-on:myEvent会转成 v-on:myevent,这样就不会触发事件了

3.3.2.实例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <input type="text" v-model="inputValue">
    <button @click="add">增加</button>
    <ul >
        <list-item
                v-for="(todo,index) in todos"
                :key="index"
                :todo="todo"
                v-on:del="del_todo"
        ></list-item>
    </ul>
</div>

<script src="node_modules/vue/dist/vue.js"></script>
<script>
    Vue.component('list-item', {
        template: `<li @click="$emit('del',todo)">{{todo}}</li>`,
        props: ['todos', 'todo']
    });

    new Vue({
        el: '#app',
        data: {
            inputValue: '',
            todos: []
        },
        methods: {
            add(){
                this.todos.push(this.inputValue);
                this.inputValue = ''
            },
            del_todo(todo){
                this.todos = this.todos.filter((item)=>{
                    return item !== todo
                })

            }

        }
    })
</script>
</body>
</html>

螺钉课堂视频课程地址:http://edu.nodeing.com

posted @ 2019-12-13 15:33  螺钉课堂Nodeing-com  阅读(244)  评论(0编辑  收藏  举报