vue——组件(二)

一、组件化开发基础

1 组件是什么
    扩展 HTML 元素,封装可重用的代码,目的是复用
    -例如:有一个轮播,可以在很多页面中使用,一个轮播有js,css,html
    -组件把js,css,html放到一起,有逻辑,有样式,有html
2 分类
    -全局组件
    -局部组件
3 工程化以后
    一个组件就是一个  xx.vue
    
4 element ui 其实就是写了一堆好看的组件,以后我们直接拿过来用就可以了

5 在vue中,实例就是对象

1.1定义全局组件并使用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="js/vue.js"></script>
    <title>Title</title>
</head>
<body>

<div id="box">

    <div @click="handleClick">我是根组件的div</div>
    <!--    全局组件使用-->
    <child></child>
    <ul>
        <li v-for="i in 4">{{i}}</li>
    </ul>
    <div>
        <child></child>
    </div>

</div>


</body>
<script>
    //创建组件对象(全局组件)---注意写法
    Vue.component('child', {
        //组件的模板
        template: `
            <div>
                <div style="background: red" @click="handleClick">我是头部</div>
                <div v-if="isShow">显示消失</div>
            </div>
        `,
        // 组件的方法
        methods:{
            handleClick(){
                console.log('我被点击了')
                this.isShow=!this.isShow
            }
        },
        //组件的数据
        data(){
            return {
                isShow:true
            }
        },
    })
    var vm = new Vue({
        el: '#box',
        data: {
            isShow:true,
        },
        methods:{
              handleClick(){
                console.log('根组件我被点击了')
            }
        }
    })
</script>
</html>

1.2定义局部组件并使用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="js/vue.js"></script>
    <title>Title</title>
</head>
<body>

<div id="box">

<child></child>

</div>


</body>
<script>
    //在根组件或全局组件 中定义出来局部组件(可定义多个,但必须注册)
    var vm = new Vue({
        el: '#box',
        data: {
            isShow: true,
        },
        methods: {
            handleClick() {
                console.log('根组件我被点击了')
            }
        },
        //局部组件,对象里的key值是主键名
        components:{
            child:{  //child组件名
                template:`
                <div @click="handleClick">{{name}}</div>
                `, //组件模板
                methods:{
                    handleClick(){
                        console.log('我被点了')
                    }
                },
                data(){
                    return{
                        name:'lili'
                    }
                },
            },
        }

    })

</script>
</html>

 二、组件编写方式与Vue实例的区别与联系

1 自定义组件需要有一个root element(即根element),一般包裹在一个div中,跟vue实例(对象)一样
2 父子组件的data是无法共享
3 组件可以有data,methods,computed....,但是data 必须是一个函数

总结:全局组件可以定义局部组件,局部组件只能在这个全局组件里使用;data返回的必须是个函数;数据或函数都是不共享的

代码演示

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="js/vue.js"></script>
    <title>Title</title>
</head>
<body>

<div id="box">
    <navbar></navbar>
</div>

</body>
<script>
    Vue.component('navbar', {
        template: `
        <div>
            <button @click="handleClick">返回</button>
            我是NavBar{{aa}}
            <button style="background: red">主页</button>
            <br>
            <child></child>
        </div>
    `,
        methods: {
            handleClick() {
                console.log('nav nav')
            },
        },
        components: {
            child: {
                template: `<button>儿子</button>`,
            }

        },
        data() {
            return {
                aa: 'lili'
            }
        },
    })

    var vm = new Vue({
        el: '#box',
        data: {
            isShow: true,
        },
        methods: {
            handleClick() {
                console.log('根组件我被点击了')
            }
        },
    })

</script>
</html>

三、组件通信之父传子通信

在全局组件中自定义属性(注意三种方式的不同):
    <global myname="name" myage="18"></global>
    <global :myname="name" :myage="19"></global>
    <global :myname="'Alice'" :myage="20"></global>

在组件中获取:{{myname}}   {{myage}}

代码演示

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>组件</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>

<div id="box">
    <!-- myName是自定义属性 -->
    <global myname="name" myage="18"></global>
    <global :myname="name" :myage="19"></global>
    <global :myname="'Alice'" :myage="20"></global>
</div>

</body>
<script>
    // 创建1个组件对象(全局组件/子组件)
    Vue.component('global', {
        template: `
            <div>
                <div style="background: red">全局组件/子组件</div>
                {{myname}}
                {{myage}}
            </div>
        `,
        props: ['myname', 'myage']
    })
    // 父组件
    let vm = new Vue({
        el: '#box',
        data: {
            name: 'lili'
        },
    })
</script>
</html>

3.1属性验证

#限制父传子的变量类型
props: {
    myname: String,
    isshow: Boolean
}
#父传子时候注意以下区别
<global :myname="name" :is_show="'false'"></global>
<global :myname="name" :is_show="false"></global>
<global :myname="name" :is_show="is_show"></global>

代码演示

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>组件</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>

<div id="box">
    <!-- myName是自定义属性 -->
    <!--    <global :myname="name" :is_show="'false'"></global>-->
    <global :my_name="name" :is_show="is_show"></global>
    <global :my_name="name" :is_show="false"></global>
</div>

</body>
<script>
    // 创建1个组件对象(全局组件/子组件)
    Vue.component('global', {
        template: `
            <div>
                <div style="background: red">我是子组件:{{is_show}}</div>
                <span>{{my_name}}</span>
            </div>
        `,
        props: {
            my_name: String,
            is_show: Boolean
        }
    })
    // 父组件
    let vm = new Vue({
        el: '#box',
        data: {
            name: 'lili',
            is_show: true
        },
    })
</script>
</html>

 四、组件通信之子父通信

子传父(控制子组件的显示和隐藏)
点击子组件,就会触发父组件的某个函数执行

代码演示

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>子传父</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>

<div id="box">
    <global @my_event="handleClick($event)"></global>
</div>

</body>
<script>
    // 创建1个组件对象(全局组件/子组件)
    Vue.component('global', {
        template: `
            <div>
                <div style="background: red">全局组件/子组件</div>
                <button @click="handleNav">点我</button>
            </div>
        `,
        data() {
            return {
                name: 'lili'
            }
        },
        methods: {
            handleNav() {
                console.log('我是子组件的函数')
                this.$emit('my_event', 666, 777, this.name)
            }
        }
    })
    // 父组件
    let vm = new Vue({
        el: '#box',
        data: {},
        methods: {
            handleClick(a,b,c) {
                console.log('我是父组件的函数')
                console.log(a)
                console.log(b)
                console.log(c)
            }
        }
    })
</script>
</html>

4.1 小案例

  • 子组件有1个按钮和1个输入框,子组件输入完内容后,数据在父组件中展示
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>子传父 小案例</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>

<div id="box">
    <global @my_event="handleShow($event)"></global>
    <br>
    <div>父组件接收到的数据:{{name}}</div>
</div>

</body>
<script>
    // 创建1个组件对象(全局组件/子组件)
    Vue.component('global', {
        template: `
            <div>
                <input type="text" v-model="myText">
                <button @click="handleClick">点我传数据</button>
            </div>
        `,
        data() {
            return {
                myText: ''
            }
        },
        methods: {
            handleClick() {
                this.$emit('my_event', this.myText)
            }
        }
    })
    // 父组件
    let vm = new Vue({
        el: '#box',
        data: {
            name: ''
        },
        methods: {
            handleShow(a) {
                this.name = a
            }
        }
    })
</script>
</html>

五、ref属性

#ref属性(也可实现组件间通信,子父,父子都可以使用)

ref放在标签上,拿到的是 原生的DOM节点
ref放在组件上,拿到的是 组件对象
    通过这种方式实现子传父(this.$refs.mychild.text)
    通过这种方式实现父传子(调用子组件方法传参数)

代码演示

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ref属性</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>

<div id="box">
    <input type="text" ref="myRef">
    <button @click="handleButton">点我</button>
</div>

</body>
<script>
    // 创建1个组件对象(全局组件/子组件)
    Vue.component('global', {
        template: `
            <div>
                <input type="text" v-model="myText">
            </div>
        `,
        data() {
            return {
                myText: ''
            }
        },
        methods: {
            handleClick() {
                this.$emit('my_event', this.myText)
                this.$emit('my_event', this.innerHTML)
            }
        }
    })
    // 父组件
    let vm = new Vue({
        el: '#box',
        data: {
            name: ''
        },
        methods: {
            handleShow(a) {
                this.name = a
            },
            handleButton() {
                console.log(this.$refs)
                console.log(this.$refs.myRef)
                console.log(this.$refs.myRef.value)
            }
        }
    })
</script>
</html>

六、事件总线

即:不同层级的不同组件通信

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>事件总线</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>

<div id="box">
    <global1></global1>
    <hr>
    <global2></global2>
</div>

</body>
<script>
    // 定义1个时间总线
    let bus = new Vue({})

    // 组件1
    Vue.component('global1', {
        template: `
            <div>
                <h3>组件1</h3>
                <input type="text" v-model="myText">
                <button @click="handleClick1">点我传递数据到另一个组件</button>
            </div>
        `,
        data() {
            return {
                myText: ''
            }
        },
        methods: {
            handleClick1() {
                console.log(this.myText)
                bus.$emit('any', this.myText)  // 通过事件总线发送
            }
        }
    })
    // 组件2
    Vue.component('global2', {
        template: `
            <div>
                <h3>组件2</h3>
                收到的消息是:{{recvText}}
            </div>
        `,
        data() {
            return {
                recvText: ''
            }
        },
        mounted() { // 组件的挂载(生命周期钩子函数中的1个),开始监听时间总线上的:any
            bus.$on('any', (item) => {
                console.log('收到了', item,)
                this.recvText = item
            })
        },
        methods: {}
    })
    // 父组件
    let vm = new Vue({
        el: '#box',
        data: {},
    })
</script>
</html>

七、动态组件

keep-alive可以让输入框内有的内容一致保持,不会因为切换而重置

代码演示

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
    <title>Title</title>
</head>
<body>

<div id="box">

    <ul>
        <li @click="who='child1'">首页</li>
        <li @click="who='child2'">商品</li>
        <li @click="who='child3'">订单</li>
    </ul>
    <!--<component :is="who"></component>-->
    <keep-alive>
        <component :is="who"></component>
    </keep-alive>
</div>

</body>
<script>

    var vm = new Vue({
        el: '#box',
        data: {
            who: 'child1'
        },
        components: {
            child1: {
                template: `
                <div>我是首页 
                <input type="text">
                </div>
                `,

            },
            child2: {
                template: `
                <div>我是商品 </div>
                `,

            },
            child3: {
                template: `
                <div>我是订单 </div>
                `,
            }
        }
    })

</script>
</html>

keep-alive可以让输入框内有的内容一致保持,不会因为切换而重置

原文地址:https://www.cnblogs.com/guojieying/p/14150481.html