【Vue 组件化开发 三】父组件给子组件传递数据、组件通信(父传子、子传父)、父访问子(children、ref)、动态组件(is、component)

简介: 本章学习父组件给子组件传递数据、组件通信(父传子、子传父)、父访问子(children、ref)、动态组件(is、component)。

一、父组件给子组件传递数据


1.使用props属性,父组件向子组件传递数据

const cpn = {
  template: "#cpn",
  props: { 
          cmessage: {
          type: String,
          default: 'zzzzz',
          required: true //在使用组件必传值
          }
  }
}


2.向cmessage对象传值

<div id="app">
    <cpn :cMessage="message"></cpn>
</div>
<script>    
const app = new Vue({
      el: "#app",
      data: {
        message: "你好",
        movies: ["复仇者联盟", "钢铁侠", "星际穿越", "哪吒传奇"]
      },
      components: {
        cpn
      }
    })
  </script>


2. props属性使用

1.数组写法

props: ['cmovies', 'cmessage']

2.对象写法

props: { 
          cmessage: {
          type: String,
          default: 'zzzzz',
          required: true //在使用组件必传值
          }
  }


3.props属性的类型限制

//1.类型限制(多个类使用数组)
cmovies:Array,//限制为数组类型
cmessage:String,//限制为Strin类型
cmessage:['String','Number']//限制为String或Number类型


4.props属性的默认值

// 2.提供一些默认值,以及必传值
        cmessage: {
          type: String,
          default: 'zzzzz',//默认值
       }

5.props属性的必传值

cmessage: {
          type: String,
          default: 'zzzzz',
          required: true //在使用组件必传值
        }


6.类型是Object/Array,默认值必须是一个函数

//类型是Object/Array,默认值必须是一个函数
cmovies: {
  type: Array,
  default () {
  return [1, 2, 3, 4]
  }
  },


7.自定义验证函数

vaildator: function (value) {
  //这个传递的值必须匹配下列字符串中的一个
  return ['zzzzz', 'ttttt', 'yyy'].indexOf(value) !== -1
}


8.自定义类型

function Person(firstName,lastName) {
      this.firstName = firstName
      this.lastName = lastName
    }
  cmessage:Person//限定了cmeessage必须是Person类型


二、组件通信

1 父传子

<!DOCTYPE html>
<html>
  <head>
  <meta charset="utf-8">
  <title></title>
  </head>
  <body>
  <div id="app">
    <!-- <cpn1 :msg="message"></cpn1> -->
    <!-- <cpn1 :msg="message2"></cpn1> -->
    <cpn1 :msgab="add"></cpn1>
    <h2>{{count}}</h2>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
  <script>
    const app = new Vue({
    el: "#app",
    data: {
      /* message: ['蔡英文', '吴钊燮'] */
      /* message2:{
      name:'蔡英文',
      age:56,
      sex:'女'
      } */
      count:0
    },
    methods: {
                    add:function(){
      return this.count++
      }
    },
    computed: {
    },
    components: {
      cpn1: {
      /* template: `
        <div>我是中国人{{msg.name}}{{msg.sex}}</div>
      `, */
      template: `
      <div>
        <div @click="sum">+</div>
      </div>
      `,
      props: {
        /* msg:{
        type: Array
        } */
        /* msg:{
        type: Object
        } */
        msgab:{
        type:Function
        },
      },
      methods:{
        sum(){
        this.msgab()
        }
      }
      }
    }
    })
  </script>
  </body>
</html>


2.子传父

子组件向父组件传值,使用自定义事件$emit。

<!-- 父组件 -->
  <div id="app">
    <!-- 不写参数默认传递btnClick的item -->
    <cpn @itemclick="cpnClcik"></cpn>
  </div>
  <!-- 子组件 -->
  <template id="cpn">
    <div>
      <button v-for="(item, index) in categoties" :key="index" @click="btnClick(item)">{{item.name}}</button>
    </div>
  </template>
  <script src="../js/vue.js"></script>
  <script>
    const cpn = {
      template: "#cpn",
      data() {
        return {
          categoties: [{
              id: 'aaa',
              name: '热门推荐'
            },
            {
              id: 'bbb',
              name: '手机数码'
            },
            {
              id: 'ccc',
              name: '家用家电'
            },
            {
              id: 'ddd',
              name: '电脑办公'
            },
          ]
        }
      },
      methods: {
        btnClick(item) {
          this.$emit('itemclick', item)
        }
      },
    };
    const app = new Vue({
      el: "#app",
      data() {
        return {
        }
      },
      methods: {
        cpnClcik(item) {
          console.log('cpnClick'+item.name);
        }
      },
      components: {
        cpn
      },
    })
  </script>


1.在子组件中定义一个方法btnClick(item),使用$emit,'itemclick'是事件名,item是传过去的值。

methods: {
        btnClick(item) {
          this.$emit('itemclick', item)
        }
      },


2.在子组件中监听点击事件并回调此方法

<div>
      <button v-for="(item, index) in categoties" :key="index" @click="btnClick(item)">{{item.name}}</button>
</div>


3.在父组件中定义一个方法cpnClcik(item)

methods: {
  cpnClcik(item) {
  console.log('cpnClick'+item.name);
  }
},


4.并在父组件(vue实例)中调用(不写参数默认传递btnClick的item ),父组件监听事件名为itemclick的子组件传过来的事件。



三、父访问子(children、ref)


1.children、ref基本用法

父组件访问子组件,有时候需要直接操作子组件的方法,或是属性,此时需要用到$children和$ref。


使用this.$children直接获取**当前实例的直接子组件,需要注意 $children 并不保证顺序,也不是响应式的。**如果你发现自己正在尝试使用 $children 来进行数据绑定,考虑使用一个数组配合 v-for 来生成子组件,并且使用 Array 作为真正的来源。

<!-- 父组件 -->
  <div id="app">
    <cpn></cpn>
    <cpn></cpn>
    <cpn ref="aaa"></cpn>
    <button @click="btnClick" >按钮</button>
  </div>
  <!-- 子组件 -->
  <template id="cpn">
    <div>
      我是子组件
    </div>
  </template>
  <script src="../js/vue.js"></script>
  <script>
    // 父传子:props
    const cpn = {
      template: "#cpn",
      data() {
        return {
          name:"我是子组件的name"
        }
      },
      methods: {
        showMessage(){
          console.log("showMessage");
        }
      },
    };
    const app = new Vue({
      el: "#app",
      data() {
        return {
          message:"hello"
        }
      },
      methods: {
        btnClick(){
          // 1.children
          // console.log(this.$children[0].showMessage)
          // for (let cpn of this.$children) {
          //   console.log(cpn.showMessage)
          // }
          // 2.$ref
          console.log(this.$refs.aaa.name)
        }
      },
      components: {
        cpn
      },
    })
  </script>
$children方式
// 1.children
console.log(this.$children[0].showMessage)
for (let cpn of this.$children) {
    console.log(cpn.showMessage)
}


$refs方式:ref 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例


2.ref的基本使用 用在元素上

ref的基本使用 用在元素上

<!DOCTYPE html>
<html>
  <head>
  <meta charset="utf-8">
  <title></title>
  </head>
  <body>
  <div id="app">
          <p ref="p" @click="handelClick" id="ppp">hello</p>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
  <script>
    const app = new Vue({
    el: "#app",
    data: {
    },
    methods: {
                 handelClick(){
      console.log(this.$refs.p);
      const ppp = document.querySelector('#ppp')
      console.log(ppp);
     }
    },
    computed:{
    }
    })
  </script>
  </body>
</html>


3.ref在子组件上的使用

1. ref可以调用组件中的数据

<!DOCTYPE html>
<html>
  <head>
  <meta charset="utf-8">
  <title></title>
  </head>
  <body>
  <div id="app">
           <counter ref="one" @change="handelChange"></counter>
     <counter ref="two" @change="handelChange"></counter>
     <div>total:{{total}}</div>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
  <script>
    Vue.component('counter',{
    template:'<div @click="handelclick">{{number}}</div>',
    data(){
      return {
      number:0
      }
    },
    methods:{
      handelclick(){
      this.number++;
      this.$emit('change');
      }
    }
    })
    const app = new Vue({
    el: "#app",
    data: {
      total:0
    },
    methods: {
                 handelChange(){
      this.total = this.$refs.one.number + this.$refs.two.number
     }
    },
    computed:{
    }
    })
  </script>
  </body>
</html>


2.ref可以调用组件中的方法

<!DOCTYPE html>
<html>
  <head>
  <meta charset="utf-8">
  <title></title>
  </head>
  <body>
  <div id="app">
              <helloworld ref="hello"></helloworld>
              <button @click="getHello">获取helloworld组件中的值</button>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
  <script>
    Vue.component('helloworld',{
    template:'<div></div>',
    data(){
      return {
      number:0
      }
    },
    methods:{
      handelclick(){
      console.log('被调用了');
      }
    }
    })
    const app = new Vue({
    el: "#app",
    data: {
    },
    methods: {
                  getHello(){
        this.$refs.hello.handelclick();
                      console.log(this.$refs.hello.number);
        console.log(this.$refs.hello.$el.innerHTML);
      }
    },
    computed:{
    }
    })
  </script>
  </body>
</html>


四、动态组件(is、component)


1.is用于动态组件且基于 DOM 内模板的限制来工作。

基于 DOM 内模板的限制来工作

<!DOCTYPE html>
<html>
  <head>
  <meta charset="utf-8">
  <title></title>
  </head>
  <body>
  <div id="app">
          <table>
     <tr is="row">
     </tr> 
    </table>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
  <script>
    Vue.component('row',{
    template:'<tr><td>111</td></tr>'
    })
    const app = new Vue({
    el: "#app",
    data() {
      return {}
    },
    methods: {
    },
    computed:{
    }
    })
  </script>
  </body>
</html>


2.动态组件component

<!DOCTYPE html>
<html>
  <head>
  <meta charset="utf-8">
  <title></title>
  </head>
  <body>
  <div id="app">
    <!-- <child-one></child-one>
    <child-two></child-two> -->
    <component :is="type"></component>
    <button @click="handerClick">点击</button>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
   <script>
    Vue.component('child-one',{
     template:'<div>child-one</div>'
    })
    Vue.component('child-two',{
      template:'<div>child-two</div>'
    })
    const app = new Vue({
    el:'#app',
    data(){
      return {
      type:'child-one'
      }
    },
    methods:{
      handerClick(){
      console.log('111');
      this.type=this.type==='child-one'?'child-two':'child-one';
      }
    }
    }) 
   </script>
  </body>
</html>


3.动态组件官网案例

这是动态组件官网案例

<!DOCTYPE html>
<html>
  <head>
  <meta charset="utf-8">
  <title></title>
  <style>
  .tab-button {
          padding: 6px 10px;
          border-top-left-radius: 3px;
          border-top-right-radius: 3px;
          border: 1px solid #ccc;
          cursor: pointer;
          background: #f0f0f0;
          margin-bottom: -1px;
          margin-right: -1px;
        }
        .tab-button:hover {
          background: #e0e0e0;
        }
        .tab-button.active {
          background: #e0e0e0;
        }
        .tab {
          border: 1px solid #ccc;
          padding: 10px;
        }
  </style>
  </head>
  <body>
  <div id="app">
    <button v-for="(tab,index) in tabs":key="index" @click="handelclick(tab)" :class="getStyle(tab)">{{tab}}</button>
    <component :is="currentTabComponent"></component>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
   <script>
    Vue.component('tab-home',{
    template:'<div>child-one</div>'
    })
    Vue.component('tab-posts',{
    template:'<div>child-two</div>'
    })
    Vue.component('tab-archive',{
    template:'<div>child-three</div>'
    })
    const app = new Vue({
    el:'#app',
    data(){
      return {
       currentTab: "Home",
       tabs: ["Home", "Posts", "Archive"]
      }
    },
    methods:{
      handelclick(tab){
      this.currentTab = tab
      },
      getStyle(tab){
      return ['tab-button',{active:this.currentTab===tab}]
      }
    },
    computed:{
      currentTabComponent(){
      /* return `tab-${this.currentTab}`.toLowerCase() */
      return "tab-"+this.currentTab.toLowerCase()
      },
    }
    }) 
   </script>
  </body>
</html>


相关文章
|
2月前
|
JavaScript
Vue中如何实现兄弟组件之间的通信
在Vue中,兄弟组件可通过父组件中转、事件总线、Vuex/Pinia或provide/inject实现通信。小型项目推荐父组件中转或事件总线,大型项目建议使用Pinia等状态管理工具,确保数据流清晰可控,避免内存泄漏。
300 2
|
5月前
|
人工智能 JavaScript 算法
Vue 中 key 属性的深入解析:改变 key 导致组件销毁与重建
Vue 中 key 属性的深入解析:改变 key 导致组件销毁与重建
769 0
|
5月前
|
JavaScript UED
用组件懒加载优化Vue应用性能
用组件懒加载优化Vue应用性能
|
JavaScript 前端开发
简述下Vue组件化封装过程?
概念 组件系统是 Vue 的另一个重要概念,因为它是一种抽象,允许我们使用小型、独立和通常可复用的组件构建大型应用。仔细想想,几乎任意类型的应用界面都可以抽象为一个组件树: !!! 熟记 : 页面中可复用的结构、样式和功能,抽离成一个文件; 特点: 为了便于 组织和管理代码 , 便于维护和扩展维护 组件化和模块化的不同: 模块化:是从代码逻辑的角度进行划分的;方便代码分层开发,保证每个功能模块的职能单一 组件化:是从UI界面的角度进行划分的前端的组件化方便组件的重用; 全局组件 这些组件是全局注册的。
|
1月前
|
缓存 JavaScript
vue中的keep-alive问题(2)
vue中的keep-alive问题(2)
280 137
|
7月前
|
JavaScript
vue实现任务周期cron表达式选择组件
vue实现任务周期cron表达式选择组件
1006 4
|
6月前
|
JavaScript 数据可视化 前端开发
基于 Vue 与 D3 的可拖拽拓扑图技术方案及应用案例解析
本文介绍了基于Vue和D3实现可拖拽拓扑图的技术方案与应用实例。通过Vue构建用户界面和交互逻辑,结合D3强大的数据可视化能力,实现了力导向布局、节点拖拽、交互事件等功能。文章详细讲解了数据模型设计、拖拽功能实现、组件封装及高级扩展(如节点类型定制、连接样式优化等),并提供了性能优化方案以应对大数据量场景。最终,展示了基础网络拓扑、实时更新拓扑等应用实例,为开发者提供了一套完整的实现思路和实践经验。
831 77
|
4月前
|
人工智能 JSON JavaScript
VTJ.PRO 首发 MasterGo 设计智能识别引擎,秒级生成 Vue 代码
VTJ.PRO发布「AI MasterGo设计稿识别引擎」,成为全球首个支持解析MasterGo原生JSON文件并自动生成Vue组件的AI工具。通过双引擎架构,实现设计到代码全流程自动化,效率提升300%,助力企业降本增效,引领“设计即生产”新时代。
403 1
|
4月前
|
JavaScript 安全
在 Vue 中,如何在回调函数中正确使用 this?
在 Vue 中,如何在回调函数中正确使用 this?
259 0
|
7月前
|
缓存 JavaScript 前端开发
Vue 基础语法介绍
Vue 基础语法介绍