vue学习笔记day05-6.29-组件-插槽

109 阅读1分钟

组件

组件的基础使用

<!DOCTYPE html>
<html lang="en">

  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../vue.js"></script>
  </head>

  <body>
    <div id="app">
      <!-- 双闭合  组件可以重复复用 -->
      <my-component></my-component>
      <my-component></my-component>
      <my-component></my-component>
      <my-component></my-component>
      <!-- 单闭合  会阻断同名组件的渲染 一般用于结束的位置,最后一次用该组件 -->
      <my-component/>  
    </div>
    <script>
      //全局组件
      //需要注意,在模版中data是一个函数,因为数据需要从data中调用渲染到页面,但是方法只需要匹配名称原地执行即可
      Vue.component('my-component',{
        data(){
          return{
            msg:'消息123'
          }
        },
        template:`<h2 @click='add'>{{msg}}</h2>`,
        methods:{
          add:function(){
            console.log(1);
          }
        }
      })
      //这里的Vue也是一个组件
      let vm = new Vue({
        el: '#app',
        data: {
        }
      })
    </script>
  </body>
</html>

全局组件和局部组件

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../vue.js"></script>
</head>

<body>
    <div id="app">
        <!-- 组件分为全局组件和局部组件 -->
        <!-- 全局组件  可以创建多个全局组件 -->
        <assembly></assembly>
        <assembly-one></assembly-one>

        <ssemb></ssemb>
        <ssemb-one></ssemb-one>
    </div>
    <script>
        //创建全局组件   使用component 里面有两个参数,第一个是组件名,第二个是显示组件内容模版
        Vue.component('assembly', {
            template: `<h2>这是一个全局的组件</h2>`
        })
        Vue.component('assembly-one', {
            template: `<h2>这也是一个全局组件,注意命名写法<h2>`
        })

        // 定义局部组件的渲染模版
        var ssemb = {
            template: `<h2>这是一个局部组件</h2>`
        }

        var ssembs = {
            template: `<h2>这也是一个局部组件</h2>`
        }

        let vm = new Vue({
            el: '#app',
            data: {

            },
            //局部组件只能写一个components,如果需要多个局部组件,直接使用一个变量来个组件命名,然后定义这个变量的渲染模版
            components: {
                'ssemb': ssemb,
                'ssemb-one': ssembs
            }
        })
    </script>
</body>

</html>

全局组件:
可以同时创建多个,命名可以使用 -
局部组件:
只能出现一个components,需要创建多个就在里面创建多个变量来给组件名称命名,然后定义这个变量的渲染模版

插槽

插槽实现了一组内容的分发的API(出口),可以理解为是内容的一个占位符,是为了将父组件中的子组件模版数据正常显示,子组件和父组件是由程序员自己定义
插槽的类型 <slot>

  • 默认插槽 default
  • 具名插槽 name ---给插槽起了具体的名字
  • 作用域插槽 v-slot

默认插槽

在当前的模版当中创建一个插槽,可以自动匹配模版中的内容
插槽显示内容 组件显示结构

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../vue.js"></script>
</head>

<body>
    <div id="app">
        <!-- <my-component>这里是显示的插槽的内容</my-component> -->
           <alert-box>有bug</alert-box>
    </div>
    <script>

        // 默认插槽的使用---使用slot占位 只需要在组件标签内写入展示的具体内容就可以了
        // {
        //     components:{
        //         'MyComponent':{
        //             template:'<div><slot /></div>'
        //         }
        //     }
        // }
        Vue.component('alert-box', {
            template: `
            <div>
                <strong>ERROR:</strong>
                <slot>默认内容</slot>
              </div>
            `
        })
        let vm = new Vue({
            el: '#app',
            data: {

            }
        })
    </script>
</body>

</html>

image.png
如果组件中有内容就显示组件的,如果没有内容就让他显示默认的内容

具名插槽

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../vue.js"></script>
</head>

<body>
    <div id="app">
        <!-- 具名插槽的第一种用法 -->
        <!-- <alert-box>
            <p slot="header">标题信息</p>
            <p>主题内容</p>
            <p>主题内容</p>
            <p slot="footer">底部内容</p>
        </alert-box> -->

        <!-- 具名插槽的第二种用法  如果一个数据的内容数量很多 可以给到父元素绑定插槽 -->
        <alert-box>
            <template slot="header">
                <p>标题信息</p>
                <p>标题信息</p>
                <p>标题信息</p>
            </template>
            <p>主题内容</p>
            <p>主题内容</p>
            <p slot="footer">底部内容</p>
        </alert-box>

    </div>
    <script>

        //具名插槽:使用具名插槽可以进行名字的匹配,使相应的插槽加载相应的内容
        //  就是给插槽起一个名字

        Vue.component('alert-box', {
            template: `
            <div class="container">
            <header>
                <slot name="header"></slot>
            </header>
                  
            <main>
                <slot></slot>
            </main>
                  
            <footer>
                 <slot name="footer"></slot>    
            </footer>

            </div>
            `
        })
        let vm = new Vue({
            el: '#app',
            data: {

            }
        })
    </script>
</body>

</html>

image.png

作用域插槽

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../vue.js"></script>
</head>

<body>
    <div id="app">
        <!-- 在父组件使用插槽时需要访问子组件中的数据,就可以使用作用域插槽
          用法:将data变量名  作为<slot>元素的一个attribute绑定上去
           <slot :[自定义变量名]="[需要传递的数据]">
            <slot :count="count"></slot>

            在使用组件是,通过<v-slot:插槽的名字="数据别名">的方式使用-->
        <!-- 作用域插槽 -->
        <my-list>
            <!-- 默认插槽 -->
            <template v-slot:default="slotProps">
                我叫:{{slotProps.detail.name}}
                我的爱好是{{slotProps.detail.love}}
            </template>
        </my-list>
    </div>
    <script>

        Vue.component('myList', {
            template: `
            <div>
                <slot :detail="detail"></slot>
            </div>
            `,
            data: function () {
                return {
                    detail: {
                        name: '张三',
                        love: 'coding'
                    }
                }
            }
        })
        let vm = new Vue({
            el: "#app",
            data: {
               
            }
        })
    </script>
</body>

</html>

组件通信

组件的作用域是相互独立的,组件之间的数据是无法相互引用的,需要使用组件通信

父组件给子组件传值

在子组件中使用props来接受传递的参数

<!-- 父组件给子组件传值
        在子组件中使用props来接受传递的参数
        {
            props:['name']
        }

        在父组件中使用子组件
        <parent>
            <child :name="name"></child>
        </parent>
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../vue.js"></script>
</head>

<body>
    <div id="app">
        <parent></parent>
    </div>
    <script>
        //定义父组件
        Vue.component('parent', {
            //在父组件中绑定子组件中
            template: `
             <child :name="name"></child> 
            `,
            //父组件中的数据
            data: function () {
                return {
                    name: '张三',
                    age: 18
                }
            }
        })
        //定义子组件
        Vue.component('child', {
            //使用props接受父组件中的值
            props: ['name'],
            template: `
            <div>{{name}}</div>
            `
        })
        let vm = new Vue({
            el: "#app",
            data: {
            }
        })
    </script>
</body>

</html>

子组件给父组件传值

<!-- 子组件给父组件传值
子组件通过$emit传递事件给父组件,父组件通过$on监听事件

子组件中定义事件
this.$emit('事件名称','传递参数')
this.$emit('add',1111)

父组件中监听事件的触发
<child @事件名称="事件触发的方法"></child>
-->
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../vue.js"></script>
</head>
<body>
    <div id="app">
        <parent>
            <child></child>
        </parent>
    </div>
    <script>
        // 定义父组件
        Vue.component('parent', {
            //父组件接受子组件绑定的事件
            template: `
            <child :name='name' :age='age' @add2='add3'></child>
            `,
            data: function () {
                return {
                    name: '张三',
                    age: 18
                }
            },
            methods: {
                add3: function (age) {
                    this.age = age
                }
            }
        })
        // 定义子组件
        Vue.component('child', {
            props: ['name', 'age'],
            template: `
              <div>
                  {{name}}{{age}}
                  <button @click='add1'>加一岁</button>      
              </div>
            `,
            methods: {
                add1: function () {
                    //子组件注册事件
                    this.$emit('add2', this.age + 1)
                }
            }
        })
        let vm = new Vue({
            el: '#app',
            data: {
            }
        })
    </script>
</body>

</html>

兄弟组件传值

本次使用构造函数原型链的方法,将公共属性和方法放在原型对象上

<!-- 定义事件总线
      let bus = new Vue()
      Vue.prototype.bus=bus

      定义发送的事件
      this.bus.$emit('事件名称',data)

      定义接受的事件 并在回调函数中接受参数
      this.bus.$on('事件名称',(data)=>{
           //数据的处理
      })
    -->
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../vue.js"></script>
</head>

<body>
    <div id="app">
        <person></person>
        <detail></detail>
    </div>
    <script>
        let bus = new Vue()
        Vue.prototype.bus = bus
        Vue.component('person', {
            template: `
              <div>
                <div>姓名: <input type="text" v-model="name"></div>
                <div>年龄: <input type="text" v-model="count"></div>
                    <button @click="modify">修改</button>
                </div>
            `,
            data() {
                return {
                    name: '张三',
                    count: 10
                }
            },
            methods: {
                modify: function () {
                    this.bus.$emit('modify', { name: this.name, count: this.count })
                }
            }
        })
        Vue.component('detail', {
            template: `
            <div>我是:{{name}},今年{{count}}岁了</div>
            `,
            data(){
                return {
                    name: '李四',
                    count: 18
                }
            },
            mounted() {
                this.bus.$on('modify', (detail) => {
                    this.name = detail.name
                    this.count = detail.count
                })
            }
        })
        let vm = new Vue({
            el: '#app',
            data: {
            }
        })
    </script>
</body>

</html>

动态组件

<!-- 
通过使用<component>元素,动态的把组件名绑定到is特性上  可以实现动态切换

keep-alive:缓存组件
activated 和 deactivated
activated:进入组件时触发
deactivated: 退出组件时触发

include和exclude
include可以是表达式 也可以是正则  名称匹配的组件被缓存
exclude可以是表达式 也可以是正则  名称匹配的组件不被缓存
-->
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../vue.js"></script>
</head>

<body>
    <div id="app">
        <!-- 把要缓存的组件房间keep-alibe标签里 -->
        <keep-alive>
            <component :is="currentview"></component>
        </keep-alive>
        <button @click="changeView('A')">组件A</button>
        <button @click="changeView('B')">组件B</button>
        <button @click="changeView('C')">组件C</button>
        <button @click="changeView('D')">组件D</button>
    </div>
    <script>
        Vue.component('ComponentA', {
            template: `<div>人生若只如初见</div>`,
            created() {
                console.log('组件A created');
            },
            activated() {
                console.log('进入A被触发');
            },
            deactivated() {
                console.log('退出A被触发');
            }
        })
        Vue.component('ComponentB', {
            template: `<div>何事秋风悲画扇</div>`,
            created() {
                console.log('组件B created');
            },
            activated() {
                console.log('进入B被触发');
            },
            deactivated() {
                console.log('退出A被触发');
            }
        })
        Vue.component('ComponentC', {
            template: `<div>此情可待成追忆</div>`,
            created() {
                console.log('组件C created');
            },
            activated() {
                console.log('进入C被触发');
            },
            deactivated() {
                console.log('退出A被触发');
            }
        })
        Vue.component('ComponentD', {
            template: `<div>只是当时已惘然</div>`,
            created() {
                console.log('组件D created');
            },
            activated() {
                console.log('进入D被触发');
            },
            deactivated() {
                console.log('退出A被触发');
            }
        })
        let vm = new Vue({
            el: '#app',
            data: function () {
                return {
                    currentview: 'ComponentC'
                }
            },
            methods: {
                changeView: function (name) {
                    this.currentview = `Component${name}`
                }
            }
        })
    </script>
</body>

</html>

image.png
image.png