Vuevue前端开发那些事儿

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

2021-05-08  本文已影响0人  大佬教我写程序

修饰符

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

组件化开发

<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 type="text/x-template" id="cpn">
    <div>
      <h2>欢迎使用组件化开发</h2>
      <p>这里是内容</p>
      <p>哈哈哈</p>
    </div>
  </script>
 <template id="cpn">
        <div>
          <h2>欢迎使用组件化开发</h2>
      <p>这里是内容</p>
      <p>哈哈哈</p>
    </div>
    </template>

在模板里面添加数据

     <template id="cpn">
             <div>
          <h2>{{title}}</h2>
              <p>这里是内容</p>
              <p>哈哈哈</p>
            </div>
    </template>
    Vue.component('mycpn', {
      template: '#cpn',
      data() {
        return {
          title: '我是标题'
        }
      }
    })

组件通信

父到子通信
image.png
 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]
          }
        }
      }
    }

在父组件中的自定义标签中,添加标签属性,那么在子标签中添加 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);
                }
              }
            }
          }
        }
      }
    })

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

父组件添加新属性:

provide:{
name:"why"
age:18
}

子组件也添加新属性

inject:["name","age"]

事件总线

image.png

在Vue2中

image.png

在Vue3中

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

 btnClick() {
        console.log("about按钮的点击");
        emitter.emit("why", {name: "why", age: 18});
        // emitter.emit("kobe", {name: "kobe", age: 30});
      }
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);
      })
    }

插槽<slot></slot>

具名slot

插槽作用域改变

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

动态组件

keep-alive

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

image.png

异步组件

  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

上一篇下一篇

猜你喜欢

热点阅读