Vue组件传值详解

Vue的组件传值

首先Vue我认为有几个最大的特点,

  • 第一点数据驱动,无需手动操作dom。以及MVVM模式
  • 第二点支持模块化开发
  • vNode虚拟dom diff算法

   vue是数据驱动视图更新的框架, 所以对于vue来说组件间的数据通信非常重要,那么就需要知道在vue中组件之间存在什么样的关系, 才更容易理解他们的通信方式,并且在模块化开发时,一定是需要拆分的,也就是我们常用的路由以及组件等方式,所以衍生出了这个问题,如何进行组件之间的传值问题,又为什么必须要这么去做呢?

  • 首先模块化开发,使用的是树形结构,必须要有一个根,根组件向下传递是很容易实现的事情,定义一个属性,然后在下级组件中使用props进行接收即可。
  • 在vue中组件间的关系存在两种关系:即父子关系,和非父子关系

父级向下传递数据

<body>
    <div id="app">
        <child :day='day'></child>
	</div>
</body>

<script src="./js/vue.js"></script>
<script type="text/javascript">
    var child = {
        // props形式一:数组形式
        props: ['day'],
        // props形式二:对象形式
        props: {
            day: {
                default: '日',
                type: String
            }
        },
        template: '

星期{{day}}

'
} const vm = new Vue({ el: '#app', data: { day: '五' }, components: { child } }) </script>
  • 但是问题在于传递个子组件的值,子组件可以任意进行更改,而对于父组件来说,不仅仅只有一个子组件,这样就有可能破坏了其他子组件的引用关系,从而出现问题,并且最大的问题在于,它破坏了我们的树状结构,由下而上的更改我们父级的值,打破了规则,这是完全不能接受的。所以不能直接在子组件中去操作父组件传递过来的数据!!那么如果想要操作我们有两个取巧的方法,当然仍然遵守规则,子组件不可更改父组件内的数据。
    • 第一个方法:在子组件中自己定义一个变量去保存父组件的数据,然后修改我们保存下来的变量的值达到效果
    • 第二个方法: 使用computed来改变
    • 可以将父组件传递的数据仅作为初始化数据,接下来的数据变化时使用改变数据
 const child = {
      props: ["titleValue","propValue","x","y","z"], 
      template:`
        
{{title2}}
`
, data(){ return { /* 个人理解: 简单来说 我们将父级传递来的数据本地化,初始化 那么第一次使用的时候就是父级传递来的值,下次再改变时,也不会修改 父级传递值的内容 类似于 重新赋值 */ title: this.titleValue, // 只被渲染一次 } }, mounted () { // 单向数据流 如果在这里改变父组件传递过来的值 父级props的更新会流动到子组件中, // 但是反过来不行,这样会防止从子组件以外变更父级组件的状态,从而导致你的应用数据流难以理解 // 如果想要修改父组件传递过来的值,那么我们可以将这个值 setTimeout(()=>{ this.title="world" },2000) console.log(typeof this.propValue); }, // 方法二: 我们通过computed 来改变 computed: { title2(){ return this.title+"!!!"; } }, }

父级向下传递数据 二

  • 使用provide和inject依赖注入
    • 总是成对出现
    • 使用方法:使用provide在父组件中返回要传输的数据,使用inject在下级组件中进行注入数据
// 父组件
 provide(){
        return {
            user:this.user,
        } 
    },
// 子组件
 inject:{
        user:{
            default:()=>{}
        },
  • 另外再说一个小知识点
    const child3={   
      //如果写props验证  就可以使用传入数据在template中的标签内使用
      //如果不写 会默认将传入数据 放在组件的"根"元素上 简单的理解 就是写在了标签上(一鱼两吃!) 做了一个活口
      //inheritAttrs属性是 禁止Attribute的继承 也就是即便不写props也不会被继承
      //但是有例外 只有stype和class仍然会被设置在标签上  其他即便是id也不会被设置
      inheritAttrs: false,
      template:`
        
`
}

子级向上传递数据

  • 讲完了父组件向子组件传递,再来将子组件如何向父组件传递数据
    • 子组件模版内容中用$emit()定义自定义事件$emit()方法至少有2个参数
      • 第一个参数为自定义的事件名称(不要和内置的事件重名,例如click、change等)abc
      • 第二个参数为需要传递的数据(可选,如果传可以是任何格式的数据)
  • 父组件模板内容中的子组件占位标签上用v-on(或@)绑定子组件定义的自定义事件名,监听子组件的事件,实现通信

  • 示例代码:每点击子组件按钮给父组件字体加9像素

<body>
    <div id="app">
        <child @anlarge-text='bigger'></child>
        <p :style="{fontSize: fontSize + 'px'}">{{msg}}</p>
    </div>
</body>

<script src="./js/vue.js"></script>
<script type="text/javascript">
    // 子组件
    var child = {
        template: ``,
    }
    // 根组件(父)
    const vm = new Vue({
        el: '#app',
        data: {
            msg: 'hello vue',
            fontSize: 12
        },
        components: {
            child
        },
        methods: {
            bigger: function (n){
                this.fontSize += n
            }
        }
    })
</script>

个人理解:在这个地方,并不是很难理解,拿案例来说,如果我想点击变大,那么父组件如何知道我进行了点击,那么就通过一个自定义事件,来将父子组件联系起来,当子组件进行点击事件触发了自定义事件并且传参,那么父组件同样可以接收到自定义事件的触发,从而触发他的事件处理函数,即子组件点击->自定义事件触发->父组件触发事件处理。 通过事件的方式将数据进行了传递。

子级向上传递数据 方法二

使用$parent.获取父组件对象,然后再获取数据对象

  mounted() {
 	 this.msg2=this.$children[0].msg  
  }
  • 补充: 在父传子时同样可以使用
   this.msg22 = this.$parent.msg2;  来获取

子级向上传递数据 方法三

父去取子的数据信息。

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

  • ref放在标签上,拿到的是原生节点。ref放在组件上 拿到的是组件实例
  • 原理:在父组件中通过ref属性(会被注册到父组件的$refs对象上)拿到组件/DOM对象,从而得到组件/DOM中的所有的信息,也包括值
<!-- 普通DOM -->
<p ref="p">hello</p>
<!-- 子组件 -->
<child-comp ref="child"></child-comp>

<script>
new Vue({
    el: '#app',
    data: {

    },
    mounted: function(){
        console.log(this.$refs.p);
        console.log(this.$refs.child);
        this.$refs.comp.msg = '123' // 修改值
    }
})
</script>

**非父子传递数据 **

  • 先介绍一个Bus总线的方法
    • 那么它能够做什么呢?它不仅可以进行非父子组件的数据传输,同样可以进行父子组件的数据传输,听起来非常好用,但是它会破坏规则,并且在大型项目开发时,会导致关系混乱,所以并没有想象中那么好用
      EventBus
      在Vue中通过单独的事件中心来管理非父子关系组件(兄弟)间的通信:
      Vue组件传值详解_第1张图片
      这里来讲一下什么是Bus总线,举个栗子:某情侣因为异地分居这时候没有办法直接见到彼此,所以就每天需要电话通信,男方就是组件A,女方就是组件B,事件中心就是运营商,当男方或者女方给对方打电话时,就会触发运营商的监听事件,发送消息给另外一方就实现了通信了。
      核心步骤
  • 建立事件中心
  •   const eventBus = new Vue()
    
  • 传递数据
  •  eventBus.$emit('自定义事件名',传递的数据)
    
  • 接收数据
  •  eventBus.$on('自定义事件名'[,callback])
    
  • 销毁事件中心
  •  eventBus.$off('自定义事件名')
    

示例代码:实现回合制互相伤害

<body>
    <div id="app">
        <zj_one></zj_one>
        <hr/>
        <zj_two></zj_two>
        <hr/>
        <button @click='destoryBus'>炸掉事件中心</button>
    </div>
</body>

<script src="./js/vue.js"></script>
<script type="text/javascript">
    // 定义事件中心
    const eventBus = new Vue()

    Vue.component('zj_one',{
        data: function(){
            return {
                data: 100
            }
        },
        template: `
                
{{data}}
`
, methods:{ fn1: function(){ eventBus.$emit('zj2_event',1) } }, mounted:function(){ eventBus.$on('zj1_event',val => this.data -= val) } }) Vue.component('zj_two',{ data: function(){ return { data: 100 } }, template: `
{{data}}
`
, methods:{ fn2: function(){ eventBus.$emit('zj1_event',2) } }, mounted:function(){ eventBus.$on('zj2_event',val => this.data -= val) } }) new Vue({ el: '#app', methods: { destoryBus: function(){ // 销毁双方监听的事件 eventBus.$off('zj1_event') eventBus.$off('zj2_event') } } }) </script>

总结

Vue 推出了一个状态管理工具 Vuex,可以很方便实现组件之间的参数传递。

你可能感兴趣的:(vue,vue.js)