美文网首页Vue.js开发技巧Vue技术前端开发那些事儿
【vue】5.0 组件注册、父子传值、refs通信、bus事件总

【vue】5.0 组件注册、父子传值、refs通信、bus事件总

作者: bobokaka | 来源:发表于2021-05-29 00:21 被阅读0次
注册方式
1.全局注册

Vue.component

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Examples</title>
<meta name="description" content="">
<meta name="keywords" content="">
<link href="" rel="stylesheet">
<style>
  .navbar{
    background: red;
  }
</style>
<script type="text/javascript" src="lib/vue.js"></script>
</head>
<body>
   
    <div id="box">
      <navbar></navbar>
      
      <sidebar></sidebar>

      <navbar></navbar>

      <!-- <app-child></app-child> -->
    </div>

   
    <script type="text/javascript">
          //1. 全局定义组件 (作用域隔离)
          
          Vue.component("app-child",{
            template: `
              <div>child</div>
            `
          })


          Vue.component("navbar",{
            template: `<nav style="background:red">
              <button @click="handleClick()">返回-{{text}}</button>
              <span>导航栏</span>
              <app-child></app-child>
              <navbarchild></navbarchild>
            </nav>`,

            data(){
              return {
                text:"111111"
              }
              // 组件与组件 的状态需要相互隔离, 要设计成函数。
            },

            methods:{
              handleClick(){
                console.log("click--navbar");
                this.text="222222";
              }
            },
            components:{
              navbarchild:{
                template:`<div>navbarchild--{{title}}</div>`,
                data(){
                  return {
                    title:"111111111"
                  }
                }
              }
            }
          })

          Vue.component("sidebar",{
            template: `<div style="background:blue">
              <ul @click="handleClick">
                <li>1111</li>
                <li>2222</li>
                <li>3333</li>
              </ul>
              <app-child></app-child>
              <navbarchild></navbarchild>
            </div>`,
            methods:{
              handleClick(){
                console.log("click--sidebar");
              }
            }
          })
          

          var vm = new Vue({
            el:"#box"
          }) //根组件(root )
    </script>
</body>


</html>


2.局部组件
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Examples</title>
<meta name="description" content="">
<meta name="keywords" content="">
<link href="" rel="stylesheet">
<style>
  .navbar{
    background: red;
  }
</style>
<script type="text/javascript" src="lib/vue.js"></script>
</head>
<body>
   
    <div id="box">
      {{title}}
      <!-- <img :src="title"/> -->
      <navbar myword="home" :myshow="false"></navbar>
      <navbar myword="list" :myshow="true"></navbar>
      <navbar myword="shopcar" :myshow="true"></navbar>
      <navbar :myword="title" :myshow="true"></navbar>
      <!-- <app-child></app-child> -->
    </div>

   
    <script type="text/javascript">
          //1. 全局定义组件 (作用域隔离)
          


          Vue.component("navbar",{
            template: `<nav style="background:red">
              <button @click="handleClick()" v-show="myshow">返回-{{text}}</button>
              <span>导航栏--{{myword}}---{{myshow}}</span>
            </nav>`,

            //接受父组件传来的属性
            // props:["myword","myshow"],

            //属性验证
            props:{
              myword:String,
              myshow:Boolean
            },

            data(){
              return {
                text:"111111"
              }
              // 组件与组件 的状态需要相互隔离, 要设计成函数。
            },

            methods:{
              handleClick(){
                console.log("click--navbar");
                this.text="222222";
              }
            }
          })

       

          var vm = new Vue({
            el:"#box",
            data:{
              title:"根组件中定义的title"
            }
          }) //根组件(root )
    </script>
</body>


</html>

以上涉及到父传子,属性验证

type:String, Boolean, Array, Object, Function, Symbol
required 必填
default 默认值

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>lesson 15</title>
  <script src="https://unpkg.com/vue@next"></script>
</head>
<body>
  <div id="root"></div>
</body>
<script>
  const app = Vue.createApp({
    data() {
      return { num: 1234 }
    },
    template: `
      <div><test :content="num" /></div>
    `
  });

  // type:String, Boolean, Array, Object, Function, Symbol
  // required 必填
  // default 默认值
  app.component('test', {
    props: {
      content: {
        type: Number,
        //校验
        validator: function(value) {
          return value < 1000;
        },
        default: function() {
          return 456;
        }
      }
    },
    template: `<div>{{content}}</div>`
  });

  const vm = app.mount('#root');
</script>
</html>

单项数据流

父组件调用子组件,多个数据项可以使用一个对象进行塞值:
v-bind="params"等于子组件的
:content="params.content" :a="params.a" :b="params.b" :c="params.c"
属性传的时候,使用 content-abc 这种命名,子组件接的时候,使用 contentAbc 命名
// 单项数据流的概念: 子组件可以使用父组件传递过来的数据,但是绝对不能修改传递过来的数据

Non-prop属性

如果父组件传给子组件的参数,子组建并没有prop对应的参数来接,那么该属性将直接由子组件最外层html标签继承,这种情况就叫Non-prop属性,如何让子组件避免这种传递:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>lesson 17</title>
  <script src="https://unpkg.com/vue@next"></script>
</head>
<body>
  <div id="root"></div>
</body>
<script>
  // Non-prop 属性
  const app = Vue.createApp({
    template: `
      <div>
        <counter msg="hello"/>
      </div>
    `
  });

  app.component('counter', {
    inheritAttrs: false,
    template: `
      <div>Counter</div>
    `
  });

  const vm = app.mount('#root');
</script>
</html>

如果子组件没有最外层html标签。也可以指定某个标签继承。更可以分别继承。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>lesson 17</title>
  <script src="https://unpkg.com/vue@next"></script>
</head>
<body>
  <div id="root"></div>
</body>
<script>
  // Non-prop 属性
  const app = Vue.createApp({
    template: `
      <div>
        <counter msg="hello" msg1="hello1" />
      </div>
    `
  });

  app.component('counter', {
    // inheritAttrs: false,
    mounted() {
      console.log(this.$attrs.msg);
    },
    template: `
      <div :msg="$attrs.msg">Counter</div>
      <div v-bind="$attrs">Counter</div>
      <div :msg1="$attrs.msg1">Counter</div>
    `
  });

  const vm = app.mount('#root');
</script>
</html>

子传父

父传子属性往下传,子传父事件向上传。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Examples</title>
<meta name="description" content="">
<meta name="keywords" content="">
<link href="" rel="stylesheet">

<script type="text/javascript" src="lib/vue.js"></script>
</head>
<body>
    <div id="box">
      <child @myevent="handleMyEvent($event)"></child>
    </div>
   

    <script type="text/javascript">
        //子组件
        Vue.component("child",{
          template:`<div>
            child-<button @click="handleClick">send</button>
          </div>`,

          data(){
            return {
              money:1000000
            }
          },
          methods:{
            handleClick(){
              console.log("把消息传给父组件")
              this.$emit("myevent",this.money);// emit 分发
            }
          }
        })
       
        var vm = new Vue({
          el:"#box",
          data:{

          },

          methods:{
            handleMyEvent(data){
              console.log("我收到了钱",data)
            }
          }
        })
      

    </script>
</body>
</html>
子传父案例——卖座
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Examples</title>
<meta name="description" content="">
<meta name="keywords" content="">
<link href="" rel="stylesheet">

<script type="text/javascript" src="lib/vue.js"></script>
</head>
<body>
    <div id="box">
        <navbar @myevent="control"></navbar>
        <sidebar v-show="isShow"></sidebar>
    </div>
   
   

    <script type="text/javascript">
        //子组件
       Vue.component("navbar",{
        template:`<div>

          navbar--<button @click="handleClick">show/hide</button>
        </div>`,

        methods:{
          handleClick(){
            this.$emit("myevent");
          }
        }
       })


       Vue.component("sidebar",{
        template:`<div>

          sidebar
          <ul>
            <li>1111</li>
            <li>1111</li>
            <li>1111</li>
            <li>1111</li>
            <li>1111</li>
            <li>1111</li>
            <li>1111</li>
          </ul>
        </div>`
       })

       
        var vm = new Vue({
          el:"#box",
          data:{
            isShow:false
          },
          methods:{
            control(){
              this.isShow = !this.isShow;
            }
          }
        })
      

    </script>
</body>
</html>
ref通信
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Examples</title>
<meta name="description" content="">
<meta name="keywords" content="">
<link href="" rel="stylesheet">

<script type="text/javascript" src="lib/vue.js"></script>
</head>
<body>
    <div id="box">
      <button @click="handleClick()">get</button>
      <child ref="mychild"></child>


      <input type="text" ref="mytext"/>
      <button @click="handleAdd">add</button>

    </div>
   

    <script type="text/javascript">
        //子组件
      
        Vue.component("child",{
          template:`<div>
              child 子组件
             
          </div>`,

          data(){
            return {
              childname:"11111111111111111111"
            }
          },

          methods:{
            handleClick(data){
              console.log("child-11111",data)
            }
          }
        })

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

          },
          methods:{
            handleClick(){
              console.log(this.$refs.mychild.childname); //获取引用
            
              this.$refs.mychild.handleClick("给你5管麻药");//调用的子组件的方法
            },

            handleAdd(){
              console.log("handleAdd",this.$refs.mytext.value)
            }
          }
        })
      

    </script>
</body>
</html>
bus事件总线(组件非父子通信)

根本不在组件结构之外的对象,该如何通信?

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Examples</title>
<meta name="description" content="">
<meta name="keywords" content="">
<link href="" rel="stylesheet">

<script type="text/javascript" src="lib/vue.js"></script>
</head>
<body>
    <div id="box">
       
        <child1></child1>
        <child2></child2>
       
    </div>
   

    <script type="text/javascript">
      // eventEmitter  .on  .emit
      var bus = new Vue()// 空vue实例 中央事件总线  

      Vue.component("child1",{
        template:`<div>
          child1---<button @click="handleClick">通信</button>
        </div>`,
        methods:{
          handleClick(){
            // 向自己兄弟child1 发送一句
            // setInterval(() => {
            //   bus.$emit("kerwin","兄弟,这是麻药");
            // }, 1000)
             bus.$emit("kerwin");
          }
        },
        mounted(){
          console.log("这个函数会在child1组件创建成功后自动被vue调用")
        }
      })  



       Vue.component("child2",{
        template:`<div>
          child2--一直显示

          <ul v-show="isShow">
            <li>111111</li>
          </ul>
        </div>`,
        data(){
          return {
            isShow:true
          }
        },

        mounted(){
          console.log("这个函数会在child2组件创建成功后自动被vue调用")

          bus.$on("kerwin",(data)=>{
            // console.log(data);
            this.isShow = !this.isShow
          })
        }
      })  
     
      new Vue({
        el:"#box",
        // template:"<div>hello template</div>"
      })
   
    </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>lesson 18</title>
        <script src="https://unpkg.com/vue@next"></script>
    </head>
    <body>
        <div id="root"></div>
    </body>
    <script>
        const app = Vue.createApp({
            data() {
                return {
                    count: 1
                }
            },
            methods: {
                handleAddOne() {
                    this.count += 1;
                }
            },
            template: `
      <counter :count="count" @add-one="handleAddOne"/>
    `
        });

        app.component('counter', {
            props: ['count'],
            methods: {
                handleClick() {
                    this.$emit('addOne');
                }
            },
            template: `
      <div @click="handleClick">{{count}}</div>
    `
        });

        const vm = app.mount('#root');
    </script>
</html>

如下表示子组件传递到父组件的参数可以带数值到父组件方法:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>lesson 18</title>
        <script src="https://unpkg.com/vue@next"></script>
    </head>
    <body>
        <div id="root"></div>
    </body>
    <script>
        const app = Vue.createApp({
            data() {
                return {
                    count: 1
                }
            },
            methods: {
                handleAddOne(param) {
                    this.count += param;
                }
            },
            template: `
      <counter :count="count" @add-one="handleAddOne"/>
    `
        });

        app.component('counter', {
            props: ['count'],
            methods: {
                handleClick() {
                    this.$emit('addOne',2);
                }
            },
            template: `
      <div @click="handleClick">{{count}}</div>
    `
        });

        const vm = app.mount('#root');
    </script>
</html>

v-model使用:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>lesson 18</title>
  <script src="https://unpkg.com/vue@next"></script>
</head>
<body>
  <div id="root"></div>
</body>
<script>
  const app = Vue.createApp({
    data() {
      return { count: 1 }
    },
    template: `
      <counter v-model="count" />
    `
  });

  app.component('counter', {
    props: ['modelValue'],
    methods: {
      handleClick() {
        this.$emit('update:modelValue', this.modelValue + 3);
      }
    },
    template: `
      <div @click="handleClick">{{modelValue}}</div>
    `
  });

  const vm = app.mount('#root');
</script>
</html>

如上使用,props中必须为modelValue,触发事件也必须叫update:modelValue,但可以如下写法:

  const app = Vue.createApp({
    data() {
      return { count: 1 }
    },
    template: `
      <counter v-model:app="count" />
    `
  });

  app.component('counter', {
    props: ['app'],
    methods: {
      handleClick() {
        this.$emit('update:app', this.app + 3);
      }
    },
    template: `
      <div @click="handleClick">{{app}}</div>
    `
  });

以上可以用于父子组件双向绑定时使用。

更深入扩展,可以多参数像这样简写:

  const app = Vue.createApp({
    data() {
      return { count: 1 ,count1: 1 }
    },
    template: `
      <counter v-model:count="count" v-model:count1="count1" />
    `
  });

  app.component('counter', {
    props: ['count','count1'],
    methods: {
      handleClick() {
        this.$emit('update:count', this.count + 3);
      },
      handleClick1() {
        this.$emit('update:count1', this.count1 + 3);
      }
    },
    template: `
      <div @click="handleClick">{{count}}</div>
      <div @click="handleClick1">{{count1}}</div>
    `
  });

v-model默认绑定一个固定的参数modelModifiers,可以绑定修饰符:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>lesson 19</title>
  <script src="https://unpkg.com/vue@next"></script>
</head>
<body>
  <div id="root"></div>
</body>
<script>
  const app = Vue.createApp({
    data() {
      return {
        count: 'a',
      }
    },
    template: `
      <counter v-model.uppercase="count" />
    `
  });

  app.component('counter', {
    props: {
      'modelValue': String,
      'modelModifiers': {
      //不传递的时候,传一个空对象
        default: ()=> ({})
      }
    },
    methods: {
      handleClick() {
        let newValue = this.modelValue + 'b';
        if(this.modelModifiers.uppercase) {
          newValue = newValue.toUpperCase();
        }
        this.$emit('update:modelValue', newValue);
      },
    },
    template: `
      <div @click="handleClick">{{modelValue}}</div>
    `
  });

  const vm = app.mount('#root');
</script>
</html>

相关文章

网友评论

    本文标题:【vue】5.0 组件注册、父子传值、refs通信、bus事件总

    本文链接:https://www.haomeiwen.com/subject/rcpssltx.html