组件通信、插槽、动态组件、异步组件

修饰符

  • lazy
    <!-- lazy修饰符是当点击回车的时候绑定的值才会改变 -->
 <input type="text" v-model.lazy='age'>
  • number
        <!-- number修饰符指的是age的类型一致设置成number类型(没有的话是设置成了字符串型) -->
    <input type="text" v-model.number='age'>
  • trim
    <!-- teim是过滤掉输入时两边的空格 -->
    <input type="text" v-model.trim='message'>

组件化开发

  • 思想:提供了一种抽象,让我们可以开发出一个个独立可复用的小组件来构造我们的应用
  • 使用方法
    1.使用Vue.extend()创建出来组件构造器对象
    2.调用Vue.component()方法注册组件
    3.使用组件
<div id="app">
  <!-- 3.使用 -->
  <mycpn>
  </mycpn>
  <mycpn>
  </mycpn>
</div>

<body>
  <script src="../../node_modules/vue/dist/vue.js"></script>
  <script>
    // 1. 创建一个组件构造器对象
    const cpn = Vue.extend({
        template: `<div>
                                        <h2>欢迎使用组件化开发</h2>
                                        <p>这里是内容</p>
                                        <p>哈哈哈</p>
                                    </div>`
      })
      // 2.注册组件Vue.component('标签名', 组件构造器对象)
    Vue.component('mycpn', cpn)
    const app = new Vue({
      el: '#app',
      data: {

      }
    })
  </script>
</body>

综合写法,省略掉了Vue.extend(),但是component方法会自动调用extend函数

<div id="app">
  <!-- 3.使用 -->
  <mycpn>
  </mycpn>
</div>
    Vue.component('mycpn', {
      template: `<div>
                                        <h2>欢迎使用组件化开发</h2>
                                        <p>这里是内容</p>
                                        <p>哈哈哈</p>
                                    </div>`
    })

全局组件和局部组件

image.png

模板的两种写法

创建构造器&&注册组件

Vue.component('mycpn', {
      template: '#cpn'
    })
  • <script>标签
 <script type="text/x-template" id="cpn">
    <div>
      <h2>欢迎使用组件化开发</h2>
      <p>这里是内容</p>
      <p>哈哈哈</p>
    </div>
  </script>
  • <template>标签
 <template id="cpn">
        <div>
          <h2>欢迎使用组件化开发</h2>
      <p>这里是内容</p>
      <p>哈哈哈</p>
    </div>
    </template>

在模板里面添加数据

  • 模板里面的数据要存放在data函数当中
     <template id="cpn">
             <div>
          <h2>{{title}}</h2>
              <p>这里是内容</p>
              <p>哈哈哈</p>
            </div>
    </template>
    Vue.component('mycpn', {
      template: '#cpn',
      data() {
        return {
          title: '我是标题'
        }
      }
    })
  • 为什么data是一个函数,而不是一个对象? 因为Vue让每个组件对象都返回一个新的对象,因为如果是同一个对象的,组件在多次使用后会相互影响。

组件通信

父到子通信
image.png
  • props的三种写法
 const cpn = {
      template: '#npm',
      // 1.数组类型写法
      // props: ['cmessage']
      props: {
        /* 2.类型限制
        cmessage: String */
        // 3.提供一些默认值
        cmessage: {
          type: String,
          default: 'aaaa',
          //如果没有传值,默认为aaaa,且报错
          required: true
        },
        cmovies: {
          type: Array,
          //type:object默认值必须是函数返回,目的是防止不要智指向 一个对象
          default () {
            return [111]
          }
        }
      }
    }
  • 更多写法


    image.png
  • 关于props里面驼峰命名时传参的方式


    image.png


在父组件中的自定义标签中,添加标签属性,那么在子标签中添加 v-bind="$attrs",这样子组件中就会添加父组件自定义标签里的属性


子到父的通信
  • 子到父数据的传递需要使用自定义事件
 <div id="app">
    <mycpn @item-click='cClick'></mycpn>
  </div>
  <template id="npm">
        <div>
            <button v-for='item of students' v-on:click='btnClick(item)'>{{item.name}}</button>
        </div>
    </template>
  <script src="../../node_modules/vue/dist/vue.js"></script>
  <script>
    //定义子组件
    const cpn = {
      template: '#npm',
      data() {
        return {
          students: [{
            id: 1,
            name: 'guo'
          }, {
            id: 2,
            name: 'zhang'
          }, {
            id: 3,
            name: 'liu'
          }, {
            id: 4,
            name: 'li'
          }]
        }
      },
      methods: {
        btnClick(item) {
          this.$emit('item-click', item)
        }
      }
    }
    const app = new Vue({
      el: '#app',
      data: {

      },
      components: {
        mycpn: cpn
      },
      methods: {
        cclick(item) {
          console.log('cClick', item);
        }
      }
    })
  </script>
image.png

父子间双向通信

image.png
<body>
  <div id="app">
    <cpn :pnum1='num1' :pnum2='num2' @cchange1='fchange1' @cchange2='fchange2' @changenum1='changenum1'></cpn>
  </div>
  <template id="tem">
<div>
    <h1>props:{{pnum1}}</h1>
    <h1>data:{{cnum1}}</h1>
    <input type="text" v-bind:value='cnum1' @input='cinputchange1'>
    <h1>props:{{pnum2}}</h1>
    <h1>data:{{cnum2}}</h1>
    <input type="text" v-bind:value='cnum2' @input='cinputchange2'>
</div>
    </template>
  <script src="../../node_modules/vue/dist/vue.js"></script>
  <script>
    //子组件
    const cpn = {
        template: '#tem',
        props: {
          //只接受父级传递过来的参数,不能手动对其进行修改
          pnum1: Number,
          pnum2: Number
        },
        data() {
          //因为父级也会改变props里面的值,所以我们初始化出来一个变量,来接受父级的改变的变量
          return {
            cnum1: this.pnum1,
            cnum2: this.pnum2
          }
        },
        methods: {
          cinputchange1(event) {
            this.cnum1 = event.target.value
            this.$emit('cchange1', this.cnum1)
            this.cnum2 = this.cnum1 * 100
            this.$emit('changenum1', this.cnum1 * 100)
          },
          cinputchange2(event) {
            this.cnum2 = event.target.value
            this.$emit('cchange2', this.cnum2)
            this.cnum1 = this.cnum2 * 0.01
            this.$emit('changenum2', this.cnum1)
          }
        }
      }
      //父组件
    const app = new Vue({
      el: '#app',
      data: {
        num1: 1,
        num2: 2
      },
      components: {
        cpn
      },
      methods: {
        fchange1(pnum1) {
          this.num1 = pnum1 * 1
        },
        fchange2(pnum2) {
          this.num2 = pnum2 * 1
        },
        changenum1(num) {
          this.num2 = num
        },
        changenum1(num) {
          this.num1 = num
        }
      }
    })
  </script>
</body>
image.png

父子组件通信之$children(Vue3已经弃用了)

      methods: {
        btnClick() {
          //以数组的形式输出所有的组件
          console.log(this.$children);
          //调用子组件的函数
          this.$children[0].cfn()
            //由于组件之间可能会插入其他的组件,所以但用数组的形式选择相应的子模块可能会出问题
            //refs的用法
          console.log(this.$refs); //输出一个对象,对象里包含组件中所有包含ref的组件,
          console.log(this.$refs.aaa.message) //输出子数据

        }
      }

子访问父之 $parent $root $el(可以拿到子组件整个模板)

  • 子组件应该尽量避免直接访问父组件的数据,因为这样耦合度太高了
  • 如果我们将子组件放在另外一个组件之内,很可能该父组件没有对应的属性,往往会引起问题
 const app = new Vue({
      el: '#app',
      data: {
        message: '我是父组件'
      },
      components: {
        cpn: {
          template: '#cpn',
          methods: {
            btnClick() {
              //访问父组件
              console.log(this.$parent);
              console.log(this.$parent.message);
              console.log(this.$root);
            }
          },
          components: {
            ccpn: {
              template: '#ccpn',
              methods: {
                cbtnClick() {
                  //访问根组件
                  console.log(this.$root.message);
                }
              }
            }
          }
        }
      }
    })
  • $refs能够拿到所有绑定ref的DOM元素
    image.png

非父子组件之间的访问(信息由高到低)

父组件添加新属性:

provide:{
name:"why"
age:18
}
  • provide里面的内容想要响应式处理需要用到computed,computed返回的是一个ref对象,需要取出其中的value来使用
  • 当前的this指向的是根组件本身,即this能够访问到data里面的值


    image.png

子组件也添加新属性

inject:["name","age"]

事件总线

image.png

在Vue2中

image.png

在Vue3中

如果想AB之间完成事件传递,那就要用到以下办法

  • 下载mittnpm install mitt
  • 封装一个工具
    image.png
  • 导入工具并在B里面定义事件
 btnClick() {
        console.log("about按钮的点击");
        emitter.emit("why", {name: "why", age: 18});
        // emitter.emit("kobe", {name: "kobe", age: 30});
      }
  • 在A里面监听函数
created() {
      emitter.on("why", (info) => {
        console.log("why:", info);
      });

      emitter.on("kobe", (info) => {
        console.log("kobe:", info);
      });
//所有的事件  type:事件名,info:传过来的信息
      emitter.on("*", (type, info) => {
        console.log("* listener:", type, info);
      })
    }
  • 取消事件


    image.png

插槽<slot></slot>

  • 模板中slot标签里没有内容的时候,可以通过自定义组件标签里添加内容插入
  • 模板中slot标签中有内容的时候,那就是默认插入的内容,若自定义组件标签里有内容,则会对其就行替换


    image.png

具名slot

  • 如果自定义模板标签里的内容没有写name属性,则会替换所有无名slot标签内容
    image.png

    第二种写法
  • v-slot:center 可以缩写成 #center

插槽作用域改变

image.png
 <div id="app">
    <cpn>
      <template slot-scope='info'>{{info.data.join(' - ')}}</template>
    </cpn>
  </div>
  <template id="cpn">
        <div>
            <slot :data='movies'></slot>
        </div>
    </template>

vue3中

image.png

动态组件

  • component 是内置组件,通过里面的is属性指定是哪个组件显示


    image.png

keep-alive

  • include:只有匹配到name属性的组件才会被缓存

  • exclude:匹配到任何之间的名称都不会被缓存

  • max:最多可以缓存的数目,超过这个数目之后,会把最久未使用的组件删除缓存


    image.png

在webpack打包的时候,将不同的函数分包

image.png

异步组件

  • 通过定义异步组件的方式引入组件,并注册组件之后再使用组件,那webpack在进行打包的时候会进行分包处理
  • 写法一:
  import Home from './Home.vue';
  const AsyncCategory = defineAsyncComponent(() => import("./AsyncCategory.vue"))
  • 写法二:
  const AsyncCategory = defineAsyncComponent({
    loader: () => import("./AsyncCategory.vue"),
    loadingComponent: Loading,
    // errorComponent,
    // 在显示loadingComponent组件之前, 等待多长时间
    delay: 2000,
    /**
     * err: 错误信息,
     * retry: 函数, 调用retry尝试重新加载
     * attempts: 记录尝试的次数
     */
    onError: function(err, retry, attempts) {

    }
  })

异步组件和Suspense

  • Suspense:内置的全局组件,它里面有两个插槽,一个名叫:default(默认显示),另一个是:fallback(default能显示就不会显示该组件)
  • 注册Suspense组件之后,使用组件,
    image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容

  • 1. 定义组件 语法: Vue.extend({ template: "" }) 定义组件使用Vue.exte...
    联旺阅读 498评论 0 0
  • Vue的组件化 经过两天的学习,现在终于来到了组件化开发的环节,Vue的组件化是很重要的一个点,一定要认真学习!!...
    waigo阅读 356评论 0 1
  • 组件(Component)是 Vue.js 最核心的功能,也是整个框架设计最精彩的地方,当然也是最难掌握的。本章将...
    辽A丶孙悟空阅读 542评论 1 13
  • 一,父组件向子组件传值:props 首先,准备一个父组件:father,和一个子组件:child. 现在需要把父组...
    爱学习的小丫阅读 189评论 0 0
  • 一、什么是组件化开发 人面对复杂问题的处理方式:任何一个人处理信息的逻辑能力都是有限的所以,当面对一个非常复杂的问...
    c_gentle阅读 2,101评论 0 1