浅谈Vue 2.x当中组件之间传值方式

一、父子之间传值

1、 父传子 :props 

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <div id="app">
    <my-list :list="list" :num="list.length"></my-list>
    <hr />
    <my-list></my-list>
  </div>
</body>
<template id="list">
  <ul>
    <li v-for="(item, index) of list" :key = "index">
      <img :src="item.img" alt="" style="display:block;width: 150px;height: 150px;border: 1px solid #f66">
      {{ item.title }}
    </li>
  </ul>
</template>
<script src="vue.js"></script>
<script>
  const List = {
    props: {
      list: {
        type: Array,
        default: function () {
          return [
            {
              img: '1',
              title: '您还没有传值哦'
            }
          ]
        }
      }
    },
    template: '#list'
  }
  // 全局注册组件 
  // Vue.component('my-list', List)
  new Vue({
    el: '#app',
    data: {
      list: [{
        img: 'https://m.360buyimg.com/mobilecms/s750x750_jfs/t23491/230/1714105950/260598/44036572/5b680745N534fe714.jpg!q80.dpg.webp',
        title: '七匹狼中长款夹克男春季新款时尚立领外套休闲男装茄克衫 001(黑色) 175/92A(XL)'
      }, {
        img:'https://m.360buyimg.com/mobilecms/s750x750_jfs/t23386/9/1066712099/277967/615ccafb/5b4f0e3aN262237fc.jpg!q80.dpg.webp',
        title: '【官方AppleCare+版】Apple MacBook Pro 15.4英寸笔记本电脑 深空灰色 配备Touch Bar 2018新款(八代i5/16G)'
      }]
    },
    components: {
      'my-list': List
    }
  })
</script>
</html>

2、子传父 emit 

在父组件调用子组件的地方,给它绑定一个自定义的事件,事件的执行是由父组件执行,记住不要加()

在子组件定义的地方,在需要传值的函数内部,执行 this.$emit('自定义的事件名', '传递的值') ---- 触发自定义的事件

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <div id="app">
    <h1>这里是父组件</h1>
    <h2>子组件的值是: {{ msg }}</h2>
    <my-child @to-parent="getdata"></my-child>
  </div>
</body>
<template id="child">
  <div>
    <button @click="sendData">给父组件传值</button>
  </div>
</template>
<script src="vue.js"></script>
<script>
  const Child = {
    template: '#child',
    methods: {
      sendData () {
        this.$emit('to-parent', '啦啦啦啦啊啊啦')
      }
    }
  }
  new Vue({
    el: '#app',
    data: {
      msg: ''
    },
    components: {
      'my-child': Child
    },
    methods: {
      getdata (val) {
        this.msg = val
      }
    }
  })
</script>
</html>

3、父传子 $parent 

父组件

<template>
  <div>
    <h1>父组件</h1>
    <h-child></h-child>
  </div>
</template>
<script>
  // 引入子组件
  import HChild from './Child'
  export default {
    name: 'Parent',
    components: {
      HChild
    },
    data () {
      return {
        msg: 'data from parent'
      }
    },
    methods: {
      fun () {
        console.log('parent fun')
      }
    }
  }
</script>

子组件

<template>
  <div>
    <h1>子组件</h1>
    <button @click="showParent">调用父组件的数据和方法</button>
  </div>
</template>
<script>
  export default {
    name: 'Child',
    methods: {
      showParent () {
        // 获取到所有的子组件
        console.log(this.$parent)
        // 获取指定子组件中的指定数据
        console.log(this.$parent.msg)
        // 调用子组件的方法
        this.$parent.fun()
      }
    }
  }
</script>

4、子传父 $children

子组件

<template>
  <div>
    <h1>子组件</h1>
  </div>
</template>
<script>
  export default {
    name: 'Child',
    data () {
      return {
        msg: 'msg from child'
      }
    },
    methods: {
      fun () {
        console.log('child fun')
      }
    }
  }
</script>

父组件

<template>
  <div>
    <h1>父组件</h1>
    <h-child></h-child>
  </div>
</template>
<script>
  // 引入子组件
  import HChild from './Child'
  export default {
    name: 'Parent',
    components: {
      HChild
    },
    mounted () {
      // 获取到所有的子组件,结果是一个数组
      console.log(this.$children)
      // 获取指定子组件中的指定数据
      console.log(this.$children[0].msg)
      // 调用子组件的方法
      this.$children[0].fun()
    }
  }
</script>

5、ref  (绑定字子组件上可以获取子组件中data值,绑定在dom上可获得dom元素)

父组件

<template>
    <div class="box">
        <Header >
            <div slot="left">你好</div>
            <div slot="right" @click="userFn">你好</div>
        </Header>
        <div class="content">
            <h1 ref="title" id="title">标题</h1>
            <p ref="desc" id="desc">段落描述</p>
            <button @click="getDOM">获取DOM节点</button>
            <Reftest ref="test"/>
            <button @click="getData">获取子元素数据</button>
        </div>
    </div>
</template>
<script>
  import Header from '@/mixins/header'
  import Reftest from '@/mixins/header'
  export default {
    mixins:[Header,Reftest],
    data(){
      return {
        message:'父组件'
      }
    },
    methods: {
      getDOM () {
        console.log(document.getElementById('title'))
        console.log(document.getElementById('desc'))
        console.log('----------------------')
        console.log(this.$refs.title)
        console.log(this.$refs.desc)
      },
      getData(){
        this.$refs.test.msg='奶牛'
        console.log(this.$refs.test.msg)
      },

    }
  }
</script>

子组件

<template>
  <div>
    <button @click="getData">子组件直接获取父组件的数据</button>
  </div>
</template>
<script>
export default {
  data () {
    return {
      msg: 'child-----------------------------'
    }
  },
  methods: {
    getData () {
      console.log(this.$parent.message)
    }
  }
}
</script>

6、Provide、inject (官方不推荐使用,但是写组件库时很常用)

父组件

<template>
    <div id="app">
    </div>
</template>
    <script>
        export default {
            data () {
                    return {
                        datas: [
                            {
                                id: 1,
                                label: '产品一'
                            }
                        ]
                    }
            },
            provide {
                return {
                    datas: this.datas
                }
            }
        }
    </script>

子组件

<template>
    <div>
        <ul>
        <li v-for="(item, index) in datas" :key="index">
            {{ item.label }}
        </li>
        </ul>
    </div>
</template>
    <script>
        export default {
            inject: ['datas']
        }
    </script>

 二、兄弟组件之间传值

1、利用new Vue()实例作为中央事件总线  Vue.prototype.$bus = new Vue()

在需要接收数据的组件内部,先监听某一个自定义的事件,接收传递过来的数据

在需要传递数据的组件内部的某一个函数内,去触发 一个 自定义的事件,发送传递的数据

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <div id="app">
    <my-content></my-content>
    <my-footer></my-footer>
  </div>
</body>
<template id="content">
  <div>
    内容 - {{ type }}
  </div>
</template>
<template id="footer">
  <ul>
    <li @click="changeContent('首页')">首页</li>
    <li @click="changeContent('分类')">分类</li>
    <li @click="changeContent('购物车')">购物车</li>
    <li @click="changeContent('我的')">我的</li>
  </ul>
</template>
<script src="vue.js"></script>
<script>
  const bus = new Vue()
  const Content = {
    template: '#content',
    data () {
      return {
        type: ''
      }
    },
    mounted () { // 用来监听点击的是哪一个
      bus.$on('footer-content', (val) => {
        this.type = val
      })
    }
  } 
  const Footer = {
    template: '#footer',
    methods: {
      changeContent (val) {
        bus.$emit('footer-content', val)
      }
    },
    mounted () {
      bus.$emit('footer-content', '首页')
    }
  }

  new Vue({
    el: '#app',
    components: {
      'my-content': Content,
      'my-footer': Footer
    }
  })
</script>
</html>

三、跨级组件通信

1、$attrs 接收除了props声明外的所有绑定属性(class、style除外)

//parent组件
<template>
    <div>
        <Son :name='name' :age='age'/>
    </div>
</template>
<script>
    export default {
        data() {
            return {
                name: 'Eric',
                age: '20'
            }
        }
    }
</script>

//Son组件
<template>
    <div>
        //此时Son组件把从父组件传来的数据,在传给孙组件
        <GrandSon v-bind='$attrs'/>
    </div>
</template>
<script>
    export default {
        props: ['name'],
        mounted() {
            //父组件共传来连个值,一个name, 一个age,由于name被props接收了,故$attrs 只有age属性
            console.log(this.$attrs) //{age: '20'}
        }
    }
</script>

//GrandSon组件
<template>
    <div>
        这是孙组件
    </div>
</template>
<script>
    export default {
        mounted() {
            //这样父祖组件就把数据传到了孙组件
            console.log(this.$attrs) // {age: '20'}
        }
    }
</script>

 2、$listeners 接收除了带有.native事件修饰符的所有事件监听器

//parent组件
<template>
    <div>
        <Son @eventOne='eventHandler' @click.native='clickHandler'/>
    </div>
</template>
<script>
    export default {
        methods: {
            eventHandler() {
                console.log('触发了Parent中的eventHandler')
            },
            clickHandler() {
                console.log('触发了Parent中的clickHandler')
            }
        }
    }
</script>

//Son组件
<template>
    <div>
        //此时Son组件把从父组件传来的监听器,在传给孙组件
        <GrandSon v-on='$listerners'/>
    </div>
</template>
<script>
    export default {
        mounted() {
            //父组件监听了两个事件,一个eventOne, 一个click,由于click被native修饰了,故$listerners 只有eventOne事件
            console.log(this.$listerners) //{eventOne: fn}
            this.$emit('eventOne') //可以触发Parent组件中的eventHandler函数
        }
    }
</script>

//GrandSon组件
<template>
    <div>
        这是孙组件
    </div>
</template>
<script>
    export default {
        mounted() {
            //这样孙组件通过emit触发Parent组件中的监听函数
            console.log(this.$listerners) // {eventOne: fn}
            this.$emit('eventOne') //可以触发Parent组件中的eventHandler函数
        }
    }
</script>

四、通用组件传值 Vuex

不说了 vuex yyds用就完事了

 

 

 

 

posted @ 2021-03-16 16:19  菜鸟小何  阅读(177)  评论(0编辑  收藏  举报