vuejs / vue

This is the repo for Vue 2. For Vue 3, go to https://github.com/vuejs/core
http://v2.vuejs.org
MIT License
207.74k stars 33.68k forks source link

'Global' mixin for only a component and for its children, grand children, ... #9999

Closed mudin closed 5 years ago

mudin commented 5 years ago

What problem does this feature solve?

First of all, I apology If I don't make sense.

Global Mixin is very useful feature. But there are some need to consider:

  1. It affects every single Vue instance created, including third party components.
  2. the same named data or method cannot be used for children under 2 separated parents

props, vuex or listeners are not good practice for really big project which has 30 nested components. we need to pass the same data over and over between components.

If there would be something like 'global' mixin (just global in one component and its children, grandchildren,...), and when we add it to a single component, we could use it its any level children.

What does the proposed API look like?

I am not sure about how API look like. there is an example

JS:

class User {
    constructor(name){
    this.name = name;
  }
}

// Mixins
let mixin1 = {
  data: function() {
    return {
      user: new User('user1')
    }
  },
}

let mixin2 = {
  data: function() {
    return {
      user: new User('user2'),
      msg: "this is user2's mixin"
    }
  }
}

// Child1 component
Vue.component('Child1', {
  template: '#child1'
});

// Child2 component
Vue.component('Child2', {
  template: '#child2'
});

// 2nd parent component
Vue.component('Parent2', {
  template: '#parent2',
  mixins:[mixin2]
});

// 1st parent component
Vue.component('Parent1', {
  template: '#parent1',
  mixins:[mixin1]
});

// Initialize Vue
new Vue({
  el: '#app'
})

HTML:

<!-- parent1 Template -->
<template id="parent1">
  <div  style="background:green">
    I am parent1 <br>
    username: {{user.name}}<br>
    msg: {{msg}}
    <p style="margin:10px">
      <parent2></parent2>
      <child2></child2>
    </p>
  </div>
</template>

<!-- parent2 Template -->
<template id="parent2">
  <div style="background:blue">
    I am parent2 <br>
    username: {{user.name}}<br>
    msg: {{msg}}
    <pre>
      <child1></child1>
    </pre>
  </div>
</template>

<!-- child1 Template -->
<template id="child1">
  <div  style="background:white">
    I am child 1 <br>
    username: {{user}}<br>
    msg: {{msg}}
  </div>
</template>

<!-- child2 Template -->
<template id="child2">
  <div  style="background:yellow">
    I am child 2 <br>
    username: {{user}}<br>
    msg: {{msg}}
  </div>
</template>

<!-- ------------------- -->

<div class="container">
  <div id="app">
    <parent1 />
    <parent2 />
  </div>
</div>

in any component under parent1 or parent2 components, data user, msg, .. should be accessible without updating the component code.

Thank you

posva commented 5 years ago

Hi, this is a completely implicit behaviour that would automatically break a component if used outside of other components. Because this is bug-prone and hard to maintain, we do not want to provide such implicit behaviour. Instead, this should be implemented in user-land.

The equivalent way of doing this in Vue, which is explicit, is inject/provide

mudin commented 5 years ago

@posva I got it.now I am sure that I have to implement it myself . Thank you for your feedback!

KaKi87 commented 2 years ago

This would be useful for @tolgee/vue (a vue-i18n alternative) which requires a mixin (TolgeeMixin) to be imported in each component that uses the $t method to make it work.

It can't be imported globally, but only from children of a specific top-level component (TolgeeProvider).