158-vue04-组件&组件间通信&插槽

昨日回顾

1 购物车案例
2 v-model之lazy,number,trim
	-lazy:input框的数据绑定等失去焦点以后再变化
   	-number:input框中333dsda,变成333
    -trim:input去前后空格
3 与后端交互
	-jq的ajax
	-fetche
    -axios:get,put,post,delete..(带头,带数据。。。)
    -跨域问题(如何处理)
4 与后端交互之fetche
5 与后端交互之axios
6 计算属性之首字母大写
	-函数当作变量来使用,有缓存,在页面上使用多次,只执行一次
7 通过计算属性重写过滤案例
	
8 组件定义
	-组件化开发:全局组件,局部组件
    -组件中有html,css,js:数据是独立的
## vue的开源项目,在本地运行起来(别人开源了一个djago项目,跑在本地)
1 vue项目:安装node(python解释器)---》一路下一步--》(node:python3,npm:pip)
2 使用pycharm打开vue项目
3 terminal中输入:npm install  (安装这个vue项目所有的依赖:pip3 install -r requ.txt)
4 命令行下执行:npm run serve / npm run start / npm run dev 等同于:python manage.py runserver

今日内容

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">
<child></child>
<child1></child1>
</div>
</body>
<script>

    Vue.component('child1', {
        template: `
            <div>
                <div style="background: red" @click="handleClick">我是头部</div>
                <div v-if="isShow">显示消失</div>
                <child></child>
            </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('根组件我被点击了')
            }
        },
        //局部组件
        components:{
            child:{  //child组件名
                template:`
                <div @click="handleClick">{{name}}</div>
                `, //组件模板
                methods:{
                    handleClick(){
                        console.log('我被点了')
                    }
                },
                data(){
                    return{
                        name:'lqz'
                    }
                },
            },
        }
    })
</script>
</html>

2 组件编写方式与Vue实例的区别

1 自定义组件需要有一个root element,一般包裹在一个div中,跟vue实例一样
2 父子组件的data是无法共享
3 组件可以有data,methods,computed....,但是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>
    {{aa}}
</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: 'lqz'
            }
        },
    })
    var vm = new Vue({
        el: '#box',
        data: {
            isShow: true,
        },
        methods: {
            handleClick() {
                console.log('根组件我被点击了')
            }
        },
    })

</script>
</html>

3 组件通信之父传子通信

1 父子通信
2 在全局组件上自定义属性
	<navbar myname="lqz" age="18"></navbar>
3 在组件中获取
	props: ['myname','age']  #myname=lqz   age=18
        
4 区分开这两种赋值方式
     <navbar myname="lqz" age="18"></navbar>
     <navbar :myname="'ffff'" age="19"></navbar>
     <navbar :myname="name" age="19"></navbar>

3.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">
    <!--myname是自定义属性-->
    <navbar myname="lqz" age="18"></navbar>
    <navbar :myname="'ffff'" age="19"></navbar>
</div>
</body>
<script>
    Vue.component('navbar', {
        template: `
        <div>
            <button @click="handleClick">返回</button>
            我是NavBar---{{age}}
            <button style="background: red">{{myname}}</button>
        </div>
    `,
        props: ['myname','age']
    })

    var vm = new Vue({
        el: '#box',
        data: {
            name: 'xxx',
        },
    })

</script>
</html>

3.2 属性验证

1 限制父传子的变量类型
	  props: {
            myname:String,
            isshow:Boolean,
            varies:'' //传递,但不验证类型
        }
2 父传子时注意以下的区别
    <navbar myname="lqz" :isshow="isshow"></navbar>
    <navbar myname="lqz" :isshow="false"></navbar>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="js/vue.js"></script>
    <title>Title</title>
</head>
<body>

<div id="box">
    <!--myname是自定义属性-->
<!--    <navbar myname="lqz" isshow="false"></navbar>-->
    <navbar myname="lqz" :isshow="isshow"></navbar>
    <navbar myname="lqz" :isshow="false"></navbar>

</div>


</body>
<script>
    Vue.component('navbar', {
        template: `
        <div>
            <button>返回</button>
            我是NavBar---{{isshow}}
            <button style="background: red">{{myname}}</button>
        </div>
    `,
        props: {
            myname:String,
            isshow:Boolean
        }
    })

    var vm = new Vue({
        el: '#box',
        data: {
            name: 'xxx',
            isshow:true,
        },
    })

</script>
</html>

4 组件通信之子传父通信

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">
<navbar @myevent="handleClick"></navbar>
</div>
</body>
<script>
    Vue.component('navbar', {
        template: `
        <div>
            <button @click="handleNav">点我,触发父组件的某个函数执行</button>
        </div>
    `,
        data(){
            return {
                name:'lqz'
            }
        },
        methods:{
            handleNav(){
                console.log('我是nav的函数,我执行了')
                this.$emit('myevent',100,this.name,99)
            }
        }
    })
    var vm = new Vue({
        el: '#box',
        data: {
        },
        methods:{
            handleClick(ev,a,b){
                console.log('我是父组件的函数,我执行了')
                console.log(ev)
                console.log(a)
                console.log(b)
            }
        }


    })


</script>
</html>

4.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 @myevent="handle"></child>
    <hr>
    {{name}}
</div>

</body>
<script>
    Vue.component('child', {
        template: `
        <div>
        <input type="text" v-model="mytext">
        <button @click="handleClick">点我</button>
        </div>
    `,
        data() {
            return {
                mytext: ''
            }
        },
        methods: {
            handleClick() {
                this.$emit('myevent', this.mytext)
            }
        }
    })
    var vm = new Vue({
        el: '#box',
        data: {
            name: ''
        },
        methods: {
            handle(a) {
                this.name = a
            }
        }
    })
</script>
</html>

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

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

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

<div id="box">
    <input type="text" ref="myref">

    <child ref="mychild"></child>
    <hr>
    <button @click="handleButton">点我</button>
</div>

</body>
<script>
    Vue.component('child', {
        template: `
        <div>
        <input type="text" v-model="mytext">
        <hr>
        我是子组件的input
        </div>
    `,
        data() {
            return {
                mytext: ''
            }
        },
        methods:{
            add(a){
                console.log('我是子组件的add方法')
                console.log(a)
                return '返回了'
            }
        }
    })

    var vm = new Vue({
        el: '#box',
        data: {
            name: 'asdf'
        },
        methods: {
            handle(a) {
                this.name = a
            },
            handleButton(){
                console.log(this.$refs.mychild.mytext)
                console.log(this.$refs.mychild.add(this.name))
            }
        }


    })


</script>
</html>

6 事件总线bus

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

<div id="box">

    <child1></child1>
    <hr>
    <child2></child2>

</div>

</body>
<script>

    //定义一个事件总线
    var bus=new Vue()


    //组件1
    Vue.component('child1', {
        template: `
        <div>
        <input type="text" v-model="text">
        <button @click="handleClick">点我传递数据到另一个组件</button>
        </div>
    `,
        data() {
            return {
                text: ''
            }
        },
        methods: {
            handleClick() {
                console.log(this.text)
                bus.$emit('suibian',this.text) //通过事件总线发送
            }
        }
    })
    //组件2
    Vue.component('child2', {
        template: `
        <div>
        收到的消息是:{{recv_text}}
        </div>
    `,
        data(){
            return {
                recv_text:''
            }
        },
        mounted(){//组件挂载(生命周期钩子函数中的一个),开始监听事件总线上的随便
            bus.$on('suibian',(item)=>{
                console.log('收到了',item)
                this.recv_text=item
            })

        },
    })

    var vm = new Vue({
        el: '#box',
        data: {},

    })


</script>
</html>

7 动态组件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="js/vue.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>

8 slot插槽

8.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">
    <child1>
        <ul>
            <li v-for="i in 4">{{i}}</li>
        </ul>
    </child1>
    <hr>
    <child2></child2>
    <hr>
    <child3></child3>
</div>

</body>
<script>

    var vm = new Vue({
        el: '#box',
        data: {
            who: 'child1'
        },
        components: {
            child1: {
                template: `

                <div>


                <slot></slot>
                <hr>
                我是首页

                <input type="text">

                </div>
                `,

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

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

            }
        }

    })


</script>
</html>

8.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">
    <child1>
        <button @click="isShow=!isShow">点我隐藏child2</button>
    </child1>
    <hr>
    <child2 v-if="isShow"></child2>
</div>

</body>
<script>

    var vm = new Vue({
        el: '#box',
        data: {
            isShow: true,
        },
        components: {
            child1: {
                template: `

                <div>
                <slot></slot>
                </div>
                `,

            },
            child2: {
                template: `
                <div>
                 <ul>
                 <li v-for="i in 4">{{i}}</li>
                </ul>
                 </div>
                `,

            },
     }

    })


</script>
</html>

8.3 具名插槽(指定标签放到组件的某个插槽中)

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

<div id="box">
    <child1>
        <button @click="isShow=!isShow" slot="button1">点我隐藏child2</button>

        <div slot="div1">我是div</div>
    </child1>
    <hr>
    <child2 v-if="isShow"></child2>
</div>

</body>
<script>

    var vm = new Vue({
        el: '#box',
        data: {
            isShow: true,
        },
        components: {
            child1: {
                template: `

                <div>
                <slot name="button1"></slot>
                <hr>
                我是华丽的分割线
                <hr>
                <slot name="div1"></slot>
                </div>
                `,

            },
            child2: {
                template: `
                <div>
                 <ul>
                 <li v-for="i in 4">{{i}}</li>
                </ul>
                 </div>
                `,

            },
     }

    })


</script>
</html>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值