Skip to content

Vue-Mixin #10

Description

@isNeilLin

在 Vue.js 中使用Mixin —— CSS-Tricks

本文转载自:众成翻译
译者:chechengpeng
审校: betsey
链接:http://www.zcfy.cc/article/3257
原文:https://css-tricks.com/using-mixins-vue-js/?utm_campaign=Revue%20newsletter&utm_medium=Newsletter&utm_source=revue

有一种很常见的情况:有两个非常相似的组件,他们的基本功能是一样的,但他们之间又存在着足够的差异性,此时的你就像是来到了一个分岔路口:我是把它拆分成两个不同的组件呢?还是保留为一个组件,然后通过props传值来创造差异性从而进行区分呢?

两种解决方案都不够完美:如果拆分成两个组件,你就不得不冒着一旦功能变动就要在两个文件中更新代码的风险,这违背了 DRY 原则。反之,太多的props传值会很快变得混乱不堪,从而迫使维护者(即便这个人是你)在使用组件的时候必须理解一大段的上下文,拖慢写码速度。

使用Mixin。Vue 中的Mixin对编写函数式风格的代码很有用,因为函数式编程就是通过减少移动的部分让代码更好理解(引自 Michael Feathers )。Mixin允许你封装一块在应用的其他组件中都可以使用的函数。如果使用姿势得当,他们不会改变函数作用域外部的任何东西,因此哪怕执行多次,只要是同样的输入你总是能得到一样的值,真的很强大!

基础实例

我们有一对不同的组件,它们的作用是通过切换状态(Boolean类型)来展示或者隐藏模态框或提示框。这些提示框和模态框除了功能相似以外,没有其他共同点:它们看起来不一样,用法不一样,但是逻辑一样。

// 模态框constModal={template: '#modal',data(){return{isShowing: false}},methods: {toggleShow(){this.isShowing=!this.isShowing;}},components: {appChild: Child}}// 提示框constTooltip={template: '#tooltip',data(){return{isShowing: false}},methods: {toggleShow(){this.isShowing=!this.isShowing;}},components: {appChild: Child}}

我们可以在这里提取逻辑并创建可以被重用的项:

const toggle = {
data() {
return {
isShowing: false
}
},
methods: {
toggleShow() {
this.isShowing = !this.isShowing;
}
}
}
const Modal = {
template: '#modal',
mixins: [toggle],
components: {
appChild: Child
}
};
const Tooltip = {
template: '#tooltip',
mixins: [toggle],
components: {
appChild: Child
}
};

你可以点击这里,查看 Sarah Drasner(@sdras) 在CodePen上编写 Mixin 的例子

为了更容易理解Mixin,这个例子故意编写得简单一些。真实应用中Mixin有如下的应用,但是它的作用也不仅限于此:获取视窗和组件的尺寸,采集特定的鼠标事件和图表的基本元素。Paul Pflugradt 有一个关于 Vue Mixins 的优秀项目,值得一提的是它是用 coffeescript 编写的。

用法

上面这个codepen的例子并没有告诉我们在一个真实的应用中如何使用Mixin,所以我们看看下面的这个。

你可以按照你喜欢的任意方式设置你的目录结构,但为了结构规整我喜欢新建一个mixin目录。我们创建的这个文件含有.js扩展名(跟.vue相对,就像我们的其他文件),为了使用Mixin我们需要输出一个对象。

directory structure shows mixins in a folder in components directory

接着我们可以在Modal.vue使用这样的写法,来引入这个Mixin:

import Child from './Child'
import { toggle } from './mixins/toggle'
export default {
name: 'modal',
mixins: [toggle],
components: {
appChild: Child
}
}

即便我们使用的是一个对象而不是一个组件,生命周期函数对我们来说仍然是可用的,理解这点很重要。我们也可以这里使用mounted()钩子函数,它将被应用于组件的生命周期上。这种工作方式真的很灵活也很强大。

合并

在下面的这个例子,我们可以看到,我们不仅仅是实现了自己想要的功能,并且Mixin中的生命周期的钩子也同样是可用的。因此,当我们在组件上应用Mixin的时候,有可能组件与Mixin中都定义了相同的生命周期钩子,这时候钩子的执行顺序的问题凸显了出来。默认Mixin上会首先被注册,组件上的接着注册,这样我们就可以在组件中按需要重写Mixin中的语句。**组件拥有最终发言权。**当发生冲突并且这个组件就不得不“决定”哪个胜出的时候,这一点就显得特别重要,否则,所有的东西都被放在一个数组当中执行,Mixin将要被先推入数组,其次才是组件。

//mixin
const hi = {
mounted() {
console.log('hello from mixin!')
}
}
//vue instance or component
new Vue({
el: '#app',
mixins: [hi],
mounted() {
console.log('hello from Vue instance!')
}
});
//Output in console
> hello from mixin!
> hello from Vue instance!

如果这两个冲突了,我们看看 Vue实例或组件是如何决定输赢的:

//mixin
const hi = {
methods: {
sayHello: function() {
console.log('hello from mixin!')
}
},
mounted() {
this.sayHello()
}
}
//vue instance or component
new Vue({
el: '#app',
mixins: [hi],
methods: {
sayHello: function() {
console.log('hello from Vue instance!')
}
},
mounted() {
this.sayHello()
}
})
// Output in console
> hello from Vue instance!
> hello from Vue instance!

你可能已经注意到这有两个console.log而不是一个——这是因为第一个函数被调用时,没有被销毁,它只是被重写了。我们在这里调用了两次sayHello()函数。

全局Mixin

当我们使用“全局”来描述Mixin的时候,我们并不是说Mixin能够像filter,在每个组件都能被访问到。只是我们能够在组件通过mixins:[toggle]访问组件上的Mixin对象。

全局Mixin被注册到了每个单一组件上。因此,它们的使用场景极其有限并且在使用的时候我们需要非常小心。一个我能想到的用途就是类似于插件,你需要赋予它访问所有东西的权限。但即使在这种情况下,我也对你正在做事情的充满警惕,尤其当你打算为应用增加通能的时候,这样做可能对你来说是个潘多拉的盒子。

为了创建一个全局实例,我们可以把它放在Vue实例之上。在一个典型的 Vue-cli 初始化的项目中,它可能在你的main.js文件中。

Vue.mixin({
mounted() {
console.log('hello from mixin!')
}
})
new Vue({
...
})

再次提醒,小心使用它!那个console.log将会出现在每个组件上,在这个案例里还不算坏(除了控制台上有多余的输出)。但如果全局Mixin被错误的使用,你将能看到它有多可怕。

结论

Mixin对于封装一小段想要复用的代码来讲是有用的。对你来说Mixin当然不是唯一可行的选择:比如说高阶组件就允许你组合相似函数,Mixin只是的一种实现方式。我喜欢Mixin,因为我不需要传递状态,但是这种模式当然也可能会被滥用,所以,仔细思考下哪种选择对你的应用最有意义吧!

Metadata

Metadata

Assignees

No one assigned

    Labels

    框架&工具库Vue和React等前端框架或工具库相关

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    , 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
     blocks
    (function() {
    function addCopyButtons() {
    document.querySelectorAll('pre code').forEach(function(codeBlock) {
    if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
    codeBlock.parentElement.setAttribute('data-copy-added', 'true');
    var btn = document.createElement('button');
    btn.textContent = 'Copy';
    btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
    btn.onmouseover = function() { this.style.opacity = '1'; };
    btn.onmouseout = function() { this.style.opacity = '0.7'; };
    btn.onclick = function() {
    navigator.clipboard.writeText(codeBlock.textContent).then(function() {
    btn.textContent = 'Copied!';
    setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
    });
    };
    codeBlock.parentElement.style.position = 'relative';
    codeBlock.parentElement.appendChild(btn);
    });
    }
    addCopyButtons();
    // Re-run on dynamic content
    var observer = new MutationObserver(addCopyButtons);
    observer.observe(document.body, { childList: true, subtree: true });
    })();
    }
    } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
    })();
    (function(){
    try {
    var __m = "github.com";
    var __re = new RegExp('^' + "github\\.com" + '
    Vue-Mixin · Issue #10 · isNeilLin/note · GitHub
    Skip to content

    Vue-Mixin #10

    Description

    @isNeilLin

    在 Vue.js 中使用Mixin —— CSS-Tricks

    本文转载自:众成翻译
    译者:chechengpeng
    审校: betsey
    链接:http://www.zcfy.cc/article/3257
    原文:https://css-tricks.com/using-mixins-vue-js/?utm_campaign=Revue%20newsletter&utm_medium=Newsletter&utm_source=revue

    有一种很常见的情况:有两个非常相似的组件,他们的基本功能是一样的,但他们之间又存在着足够的差异性,此时的你就像是来到了一个分岔路口:我是把它拆分成两个不同的组件呢?还是保留为一个组件,然后通过props传值来创造差异性从而进行区分呢?

    两种解决方案都不够完美:如果拆分成两个组件,你就不得不冒着一旦功能变动就要在两个文件中更新代码的风险,这违背了 DRY 原则。反之,太多的props传值会很快变得混乱不堪,从而迫使维护者(即便这个人是你)在使用组件的时候必须理解一大段的上下文,拖慢写码速度。

    使用Mixin。Vue 中的Mixin对编写函数式风格的代码很有用,因为函数式编程就是通过减少移动的部分让代码更好理解(引自 Michael Feathers )。Mixin允许你封装一块在应用的其他组件中都可以使用的函数。如果使用姿势得当,他们不会改变函数作用域外部的任何东西,因此哪怕执行多次,只要是同样的输入你总是能得到一样的值,真的很强大!

    基础实例

    我们有一对不同的组件,它们的作用是通过切换状态(Boolean类型)来展示或者隐藏模态框或提示框。这些提示框和模态框除了功能相似以外,没有其他共同点:它们看起来不一样,用法不一样,但是逻辑一样。

    // 模态框constModal={template: '#modal',data(){return{isShowing: false}},methods: {toggleShow(){this.isShowing=!this.isShowing;}},components: {appChild: Child}}// 提示框constTooltip={template: '#tooltip',data(){return{isShowing: false}},methods: {toggleShow(){this.isShowing=!this.isShowing;}},components: {appChild: Child}}

    我们可以在这里提取逻辑并创建可以被重用的项:

    const toggle = {
    data() {
    return {
    isShowing: false
    }
    },
    methods: {
    toggleShow() {
    this.isShowing = !this.isShowing;
    }
    }
    }
    const Modal = {
    template: '#modal',
    mixins: [toggle],
    components: {
    appChild: Child
    }
    };
    const Tooltip = {
    template: '#tooltip',
    mixins: [toggle],
    components: {
    appChild: Child
    }
    };
    

    你可以点击这里,查看 Sarah Drasner(@sdras) 在CodePen上编写 Mixin 的例子

    为了更容易理解Mixin,这个例子故意编写得简单一些。真实应用中Mixin有如下的应用,但是它的作用也不仅限于此:获取视窗和组件的尺寸,采集特定的鼠标事件和图表的基本元素。Paul Pflugradt 有一个关于 Vue Mixins 的优秀项目,值得一提的是它是用 coffeescript 编写的。

    用法

    上面这个codepen的例子并没有告诉我们在一个真实的应用中如何使用Mixin,所以我们看看下面的这个。

    你可以按照你喜欢的任意方式设置你的目录结构,但为了结构规整我喜欢新建一个mixin目录。我们创建的这个文件含有.js扩展名(跟.vue相对,就像我们的其他文件),为了使用Mixin我们需要输出一个对象。

    directory structure shows mixins in a folder in components directory

    接着我们可以在Modal.vue使用这样的写法,来引入这个Mixin:

    import Child from './Child'
    import { toggle } from './mixins/toggle'
    export default {
    name: 'modal',
    mixins: [toggle],
    components: {
    appChild: Child
    }
    }
    

    即便我们使用的是一个对象而不是一个组件,生命周期函数对我们来说仍然是可用的,理解这点很重要。我们也可以这里使用mounted()钩子函数,它将被应用于组件的生命周期上。这种工作方式真的很灵活也很强大。

    合并

    在下面的这个例子,我们可以看到,我们不仅仅是实现了自己想要的功能,并且Mixin中的生命周期的钩子也同样是可用的。因此,当我们在组件上应用Mixin的时候,有可能组件与Mixin中都定义了相同的生命周期钩子,这时候钩子的执行顺序的问题凸显了出来。默认Mixin上会首先被注册,组件上的接着注册,这样我们就可以在组件中按需要重写Mixin中的语句。**组件拥有最终发言权。**当发生冲突并且这个组件就不得不“决定”哪个胜出的时候,这一点就显得特别重要,否则,所有的东西都被放在一个数组当中执行,Mixin将要被先推入数组,其次才是组件。

    //mixin
    const hi = {
    mounted() {
    console.log('hello from mixin!')
    }
    }
    //vue instance or component
    new Vue({
    el: '#app',
    mixins: [hi],
    mounted() {
    console.log('hello from Vue instance!')
    }
    });
    //Output in console
    > hello from mixin!
    > hello from Vue instance!
    

    如果这两个冲突了,我们看看 Vue实例或组件是如何决定输赢的:

    //mixin
    const hi = {
    methods: {
    sayHello: function() {
    console.log('hello from mixin!')
    }
    },
    mounted() {
    this.sayHello()
    }
    }
    //vue instance or component
    new Vue({
    el: '#app',
    mixins: [hi],
    methods: {
    sayHello: function() {
    console.log('hello from Vue instance!')
    }
    },
    mounted() {
    this.sayHello()
    }
    })
    // Output in console
    > hello from Vue instance!
    > hello from Vue instance!
    

    你可能已经注意到这有两个console.log而不是一个——这是因为第一个函数被调用时,没有被销毁,它只是被重写了。我们在这里调用了两次sayHello()函数。

    全局Mixin

    当我们使用“全局”来描述Mixin的时候,我们并不是说Mixin能够像filter,在每个组件都能被访问到。只是我们能够在组件通过mixins:[toggle]访问组件上的Mixin对象。

    全局Mixin被注册到了每个单一组件上。因此,它们的使用场景极其有限并且在使用的时候我们需要非常小心。一个我能想到的用途就是类似于插件,你需要赋予它访问所有东西的权限。但即使在这种情况下,我也对你正在做事情的充满警惕,尤其当你打算为应用增加通能的时候,这样做可能对你来说是个潘多拉的盒子。

    为了创建一个全局实例,我们可以把它放在Vue实例之上。在一个典型的 Vue-cli 初始化的项目中,它可能在你的main.js文件中。

    Vue.mixin({
    mounted() {
    console.log('hello from mixin!')
    }
    })
    new Vue({
    ...
    })
    

    再次提醒,小心使用它!那个console.log将会出现在每个组件上,在这个案例里还不算坏(除了控制台上有多余的输出)。但如果全局Mixin被错误的使用,你将能看到它有多可怕。

    结论

    Mixin对于封装一小段想要复用的代码来讲是有用的。对你来说Mixin当然不是唯一可行的选择:比如说高阶组件就允许你组合相似函数,Mixin只是的一种实现方式。我喜欢Mixin,因为我不需要传递状态,但是这种模式当然也可能会被滥用,所以,仔细思考下哪种选择对你的应用最有意义吧!

    Metadata

    Metadata

    Assignees

    No one assigned

      Labels

      框架&工具库Vue和React等前端框架或工具库相关

      Projects

      No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      , 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Vue-Mixin · Issue #10 · isNeilLin/note · GitHub
      Skip to content

      Vue-Mixin #10

      Description

      @isNeilLin

      在 Vue.js 中使用Mixin —— CSS-Tricks

      本文转载自:众成翻译
      译者:chechengpeng
      审校: betsey
      链接:http://www.zcfy.cc/article/3257
      原文:https://css-tricks.com/using-mixins-vue-js/?utm_campaign=Revue%20newsletter&utm_medium=Newsletter&utm_source=revue

      有一种很常见的情况:有两个非常相似的组件,他们的基本功能是一样的,但他们之间又存在着足够的差异性,此时的你就像是来到了一个分岔路口:我是把它拆分成两个不同的组件呢?还是保留为一个组件,然后通过props传值来创造差异性从而进行区分呢?

      两种解决方案都不够完美:如果拆分成两个组件,你就不得不冒着一旦功能变动就要在两个文件中更新代码的风险,这违背了 DRY 原则。反之,太多的props传值会很快变得混乱不堪,从而迫使维护者(即便这个人是你)在使用组件的时候必须理解一大段的上下文,拖慢写码速度。

      使用Mixin。Vue 中的Mixin对编写函数式风格的代码很有用,因为函数式编程就是通过减少移动的部分让代码更好理解(引自 Michael Feathers )。Mixin允许你封装一块在应用的其他组件中都可以使用的函数。如果使用姿势得当,他们不会改变函数作用域外部的任何东西,因此哪怕执行多次,只要是同样的输入你总是能得到一样的值,真的很强大!

      基础实例

      我们有一对不同的组件,它们的作用是通过切换状态(Boolean类型)来展示或者隐藏模态框或提示框。这些提示框和模态框除了功能相似以外,没有其他共同点:它们看起来不一样,用法不一样,但是逻辑一样。

      // 模态框constModal={template: '#modal',data(){return{isShowing: false}},methods: {toggleShow(){this.isShowing=!this.isShowing;}},components: {appChild: Child}}// 提示框constTooltip={template: '#tooltip',data(){return{isShowing: false}},methods: {toggleShow(){this.isShowing=!this.isShowing;}},components: {appChild: Child}}

      我们可以在这里提取逻辑并创建可以被重用的项:

      const toggle = {
      data() {
      return {
      isShowing: false
      }
      },
      methods: {
      toggleShow() {
      this.isShowing = !this.isShowing;
      }
      }
      }
      const Modal = {
      template: '#modal',
      mixins: [toggle],
      components: {
      appChild: Child
      }
      };
      const Tooltip = {
      template: '#tooltip',
      mixins: [toggle],
      components: {
      appChild: Child
      }
      };
      

      你可以点击这里,查看 Sarah Drasner(@sdras) 在CodePen上编写 Mixin 的例子

      为了更容易理解Mixin,这个例子故意编写得简单一些。真实应用中Mixin有如下的应用,但是它的作用也不仅限于此:获取视窗和组件的尺寸,采集特定的鼠标事件和图表的基本元素。Paul Pflugradt 有一个关于 Vue Mixins 的优秀项目,值得一提的是它是用 coffeescript 编写的。

      用法

      上面这个codepen的例子并没有告诉我们在一个真实的应用中如何使用Mixin,所以我们看看下面的这个。

      你可以按照你喜欢的任意方式设置你的目录结构,但为了结构规整我喜欢新建一个mixin目录。我们创建的这个文件含有.js扩展名(跟.vue相对,就像我们的其他文件),为了使用Mixin我们需要输出一个对象。

      directory structure shows mixins in a folder in components directory

      接着我们可以在Modal.vue使用这样的写法,来引入这个Mixin:

      import Child from './Child'
      import { toggle } from './mixins/toggle'
      export default {
      name: 'modal',
      mixins: [toggle],
      components: {
      appChild: Child
      }
      }
      

      即便我们使用的是一个对象而不是一个组件,生命周期函数对我们来说仍然是可用的,理解这点很重要。我们也可以这里使用mounted()钩子函数,它将被应用于组件的生命周期上。这种工作方式真的很灵活也很强大。

      合并

      在下面的这个例子,我们可以看到,我们不仅仅是实现了自己想要的功能,并且Mixin中的生命周期的钩子也同样是可用的。因此,当我们在组件上应用Mixin的时候,有可能组件与Mixin中都定义了相同的生命周期钩子,这时候钩子的执行顺序的问题凸显了出来。默认Mixin上会首先被注册,组件上的接着注册,这样我们就可以在组件中按需要重写Mixin中的语句。**组件拥有最终发言权。**当发生冲突并且这个组件就不得不“决定”哪个胜出的时候,这一点就显得特别重要,否则,所有的东西都被放在一个数组当中执行,Mixin将要被先推入数组,其次才是组件。

      //mixin
      const hi = {
      mounted() {
      console.log('hello from mixin!')
      }
      }
      //vue instance or component
      new Vue({
      el: '#app',
      mixins: [hi],
      mounted() {
      console.log('hello from Vue instance!')
      }
      });
      //Output in console
      > hello from mixin!
      > hello from Vue instance!
      

      如果这两个冲突了,我们看看 Vue实例或组件是如何决定输赢的:

      //mixin
      const hi = {
      methods: {
      sayHello: function() {
      console.log('hello from mixin!')
      }
      },
      mounted() {
      this.sayHello()
      }
      }
      //vue instance or component
      new Vue({
      el: '#app',
      mixins: [hi],
      methods: {
      sayHello: function() {
      console.log('hello from Vue instance!')
      }
      },
      mounted() {
      this.sayHello()
      }
      })
      // Output in console
      > hello from Vue instance!
      > hello from Vue instance!
      

      你可能已经注意到这有两个console.log而不是一个——这是因为第一个函数被调用时,没有被销毁,它只是被重写了。我们在这里调用了两次sayHello()函数。

      全局Mixin

      当我们使用“全局”来描述Mixin的时候,我们并不是说Mixin能够像filter,在每个组件都能被访问到。只是我们能够在组件通过mixins:[toggle]访问组件上的Mixin对象。

      全局Mixin被注册到了每个单一组件上。因此,它们的使用场景极其有限并且在使用的时候我们需要非常小心。一个我能想到的用途就是类似于插件,你需要赋予它访问所有东西的权限。但即使在这种情况下,我也对你正在做事情的充满警惕,尤其当你打算为应用增加通能的时候,这样做可能对你来说是个潘多拉的盒子。

      为了创建一个全局实例,我们可以把它放在Vue实例之上。在一个典型的 Vue-cli 初始化的项目中,它可能在你的main.js文件中。

      Vue.mixin({
      mounted() {
      console.log('hello from mixin!')
      }
      })
      new Vue({
      ...
      })
      

      再次提醒,小心使用它!那个console.log将会出现在每个组件上,在这个案例里还不算坏(除了控制台上有多余的输出)。但如果全局Mixin被错误的使用,你将能看到它有多可怕。

      结论

      Mixin对于封装一小段想要复用的代码来讲是有用的。对你来说Mixin当然不是唯一可行的选择:比如说高阶组件就允许你组合相似函数,Mixin只是的一种实现方式。我喜欢Mixin,因为我不需要传递状态,但是这种模式当然也可能会被滥用,所以,仔细思考下哪种选择对你的应用最有意义吧!

      Metadata

      Metadata

      Assignees

      No one assigned

        Labels

        框架&工具库Vue和React等前端框架或工具库相关

        Projects

        No projects

        Milestone

        No milestone

        Relationships

        None yet

        Development

        No branches or pull requests

        Issue actions

        , 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Vue-Mixin · Issue #10 · isNeilLin/note · GitHub
        Skip to content

        Vue-Mixin #10

        Description

        @isNeilLin

        在 Vue.js 中使用Mixin —— CSS-Tricks

        本文转载自:众成翻译
        译者:chechengpeng
        审校: betsey
        链接:http://www.zcfy.cc/article/3257
        原文:https://css-tricks.com/using-mixins-vue-js/?utm_campaign=Revue%20newsletter&utm_medium=Newsletter&utm_source=revue

        有一种很常见的情况:有两个非常相似的组件,他们的基本功能是一样的,但他们之间又存在着足够的差异性,此时的你就像是来到了一个分岔路口:我是把它拆分成两个不同的组件呢?还是保留为一个组件,然后通过props传值来创造差异性从而进行区分呢?

        两种解决方案都不够完美:如果拆分成两个组件,你就不得不冒着一旦功能变动就要在两个文件中更新代码的风险,这违背了 DRY 原则。反之,太多的props传值会很快变得混乱不堪,从而迫使维护者(即便这个人是你)在使用组件的时候必须理解一大段的上下文,拖慢写码速度。

        使用Mixin。Vue 中的Mixin对编写函数式风格的代码很有用,因为函数式编程就是通过减少移动的部分让代码更好理解(引自 Michael Feathers )。Mixin允许你封装一块在应用的其他组件中都可以使用的函数。如果使用姿势得当,他们不会改变函数作用域外部的任何东西,因此哪怕执行多次,只要是同样的输入你总是能得到一样的值,真的很强大!

        基础实例

        我们有一对不同的组件,它们的作用是通过切换状态(Boolean类型)来展示或者隐藏模态框或提示框。这些提示框和模态框除了功能相似以外,没有其他共同点:它们看起来不一样,用法不一样,但是逻辑一样。

        // 模态框constModal={template: '#modal',data(){return{isShowing: false}},methods: {toggleShow(){this.isShowing=!this.isShowing;}},components: {appChild: Child}}// 提示框constTooltip={template: '#tooltip',data(){return{isShowing: false}},methods: {toggleShow(){this.isShowing=!this.isShowing;}},components: {appChild: Child}}

        我们可以在这里提取逻辑并创建可以被重用的项:

        const toggle = {
        data() {
        return {
        isShowing: false
        }
        },
        methods: {
        toggleShow() {
        this.isShowing = !this.isShowing;
        }
        }
        }
        const Modal = {
        template: '#modal',
        mixins: [toggle],
        components: {
        appChild: Child
        }
        };
        const Tooltip = {
        template: '#tooltip',
        mixins: [toggle],
        components: {
        appChild: Child
        }
        };
        

        你可以点击这里,查看 Sarah Drasner(@sdras) 在CodePen上编写 Mixin 的例子

        为了更容易理解Mixin,这个例子故意编写得简单一些。真实应用中Mixin有如下的应用,但是它的作用也不仅限于此:获取视窗和组件的尺寸,采集特定的鼠标事件和图表的基本元素。Paul Pflugradt 有一个关于 Vue Mixins 的优秀项目,值得一提的是它是用 coffeescript 编写的。

        用法

        上面这个codepen的例子并没有告诉我们在一个真实的应用中如何使用Mixin,所以我们看看下面的这个。

        你可以按照你喜欢的任意方式设置你的目录结构,但为了结构规整我喜欢新建一个mixin目录。我们创建的这个文件含有.js扩展名(跟.vue相对,就像我们的其他文件),为了使用Mixin我们需要输出一个对象。

        directory structure shows mixins in a folder in components directory

        接着我们可以在Modal.vue使用这样的写法,来引入这个Mixin:

        import Child from './Child'
        import { toggle } from './mixins/toggle'
        export default {
        name: 'modal',
        mixins: [toggle],
        components: {
        appChild: Child
        }
        }
        

        即便我们使用的是一个对象而不是一个组件,生命周期函数对我们来说仍然是可用的,理解这点很重要。我们也可以这里使用mounted()钩子函数,它将被应用于组件的生命周期上。这种工作方式真的很灵活也很强大。

        合并

        在下面的这个例子,我们可以看到,我们不仅仅是实现了自己想要的功能,并且Mixin中的生命周期的钩子也同样是可用的。因此,当我们在组件上应用Mixin的时候,有可能组件与Mixin中都定义了相同的生命周期钩子,这时候钩子的执行顺序的问题凸显了出来。默认Mixin上会首先被注册,组件上的接着注册,这样我们就可以在组件中按需要重写Mixin中的语句。**组件拥有最终发言权。**当发生冲突并且这个组件就不得不“决定”哪个胜出的时候,这一点就显得特别重要,否则,所有的东西都被放在一个数组当中执行,Mixin将要被先推入数组,其次才是组件。

        //mixin
        const hi = {
        mounted() {
        console.log('hello from mixin!')
        }
        }
        //vue instance or component
        new Vue({
        el: '#app',
        mixins: [hi],
        mounted() {
        console.log('hello from Vue instance!')
        }
        });
        //Output in console
        > hello from mixin!
        > hello from Vue instance!
        

        如果这两个冲突了,我们看看 Vue实例或组件是如何决定输赢的:

        //mixin
        const hi = {
        methods: {
        sayHello: function() {
        console.log('hello from mixin!')
        }
        },
        mounted() {
        this.sayHello()
        }
        }
        //vue instance or component
        new Vue({
        el: '#app',
        mixins: [hi],
        methods: {
        sayHello: function() {
        console.log('hello from Vue instance!')
        }
        },
        mounted() {
        this.sayHello()
        }
        })
        // Output in console
        > hello from Vue instance!
        > hello from Vue instance!
        

        你可能已经注意到这有两个console.log而不是一个——这是因为第一个函数被调用时,没有被销毁,它只是被重写了。我们在这里调用了两次sayHello()函数。

        全局Mixin

        当我们使用“全局”来描述Mixin的时候,我们并不是说Mixin能够像filter,在每个组件都能被访问到。只是我们能够在组件通过mixins:[toggle]访问组件上的Mixin对象。

        全局Mixin被注册到了每个单一组件上。因此,它们的使用场景极其有限并且在使用的时候我们需要非常小心。一个我能想到的用途就是类似于插件,你需要赋予它访问所有东西的权限。但即使在这种情况下,我也对你正在做事情的充满警惕,尤其当你打算为应用增加通能的时候,这样做可能对你来说是个潘多拉的盒子。

        为了创建一个全局实例,我们可以把它放在Vue实例之上。在一个典型的 Vue-cli 初始化的项目中,它可能在你的main.js文件中。

        Vue.mixin({
        mounted() {
        console.log('hello from mixin!')
        }
        })
        new Vue({
        ...
        })
        

        再次提醒,小心使用它!那个console.log将会出现在每个组件上,在这个案例里还不算坏(除了控制台上有多余的输出)。但如果全局Mixin被错误的使用,你将能看到它有多可怕。

        结论

        Mixin对于封装一小段想要复用的代码来讲是有用的。对你来说Mixin当然不是唯一可行的选择:比如说高阶组件就允许你组合相似函数,Mixin只是的一种实现方式。我喜欢Mixin,因为我不需要传递状态,但是这种模式当然也可能会被滥用,所以,仔细思考下哪种选择对你的应用最有意义吧!

        Metadata

        Metadata

        Assignees

        No one assigned

          Labels

          框架&工具库Vue和React等前端框架或工具库相关

          Projects

          No projects

          Milestone

          No milestone

          Relationships

          None yet

          Development

          No branches or pull requests

          Issue actions

          , 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' Vue-Mixin · Issue #10 · isNeilLin/note · GitHub
          Skip to content

          Vue-Mixin #10

          Description

          @isNeilLin

          在 Vue.js 中使用Mixin —— CSS-Tricks

          本文转载自:众成翻译
          译者:chechengpeng
          审校: betsey
          链接:http://www.zcfy.cc/article/3257
          原文:https://css-tricks.com/using-mixins-vue-js/?utm_campaign=Revue%20newsletter&utm_medium=Newsletter&utm_source=revue

          有一种很常见的情况:有两个非常相似的组件,他们的基本功能是一样的,但他们之间又存在着足够的差异性,此时的你就像是来到了一个分岔路口:我是把它拆分成两个不同的组件呢?还是保留为一个组件,然后通过props传值来创造差异性从而进行区分呢?

          两种解决方案都不够完美:如果拆分成两个组件,你就不得不冒着一旦功能变动就要在两个文件中更新代码的风险,这违背了 DRY 原则。反之,太多的props传值会很快变得混乱不堪,从而迫使维护者(即便这个人是你)在使用组件的时候必须理解一大段的上下文,拖慢写码速度。

          使用Mixin。Vue 中的Mixin对编写函数式风格的代码很有用,因为函数式编程就是通过减少移动的部分让代码更好理解(引自 Michael Feathers )。Mixin允许你封装一块在应用的其他组件中都可以使用的函数。如果使用姿势得当,他们不会改变函数作用域外部的任何东西,因此哪怕执行多次,只要是同样的输入你总是能得到一样的值,真的很强大!

          基础实例

          我们有一对不同的组件,它们的作用是通过切换状态(Boolean类型)来展示或者隐藏模态框或提示框。这些提示框和模态框除了功能相似以外,没有其他共同点:它们看起来不一样,用法不一样,但是逻辑一样。

          // 模态框constModal={template: '#modal',data(){return{isShowing: false}},methods: {toggleShow(){this.isShowing=!this.isShowing;}},components: {appChild: Child}}// 提示框constTooltip={template: '#tooltip',data(){return{isShowing: false}},methods: {toggleShow(){this.isShowing=!this.isShowing;}},components: {appChild: Child}}

          我们可以在这里提取逻辑并创建可以被重用的项:

          const toggle = {
          data() {
          return {
          isShowing: false
          }
          },
          methods: {
          toggleShow() {
          this.isShowing = !this.isShowing;
          }
          }
          }
          const Modal = {
          template: '#modal',
          mixins: [toggle],
          components: {
          appChild: Child
          }
          };
          const Tooltip = {
          template: '#tooltip',
          mixins: [toggle],
          components: {
          appChild: Child
          }
          };
          

          你可以点击这里,查看 Sarah Drasner(@sdras) 在CodePen上编写 Mixin 的例子

          为了更容易理解Mixin,这个例子故意编写得简单一些。真实应用中Mixin有如下的应用,但是它的作用也不仅限于此:获取视窗和组件的尺寸,采集特定的鼠标事件和图表的基本元素。Paul Pflugradt 有一个关于 Vue Mixins 的优秀项目,值得一提的是它是用 coffeescript 编写的。

          用法

          上面这个codepen的例子并没有告诉我们在一个真实的应用中如何使用Mixin,所以我们看看下面的这个。

          你可以按照你喜欢的任意方式设置你的目录结构,但为了结构规整我喜欢新建一个mixin目录。我们创建的这个文件含有.js扩展名(跟.vue相对,就像我们的其他文件),为了使用Mixin我们需要输出一个对象。

          directory structure shows mixins in a folder in components directory

          接着我们可以在Modal.vue使用这样的写法,来引入这个Mixin:

          import Child from './Child'
          import { toggle } from './mixins/toggle'
          export default {
          name: 'modal',
          mixins: [toggle],
          components: {
          appChild: Child
          }
          }
          

          即便我们使用的是一个对象而不是一个组件,生命周期函数对我们来说仍然是可用的,理解这点很重要。我们也可以这里使用mounted()钩子函数,它将被应用于组件的生命周期上。这种工作方式真的很灵活也很强大。

          合并

          在下面的这个例子,我们可以看到,我们不仅仅是实现了自己想要的功能,并且Mixin中的生命周期的钩子也同样是可用的。因此,当我们在组件上应用Mixin的时候,有可能组件与Mixin中都定义了相同的生命周期钩子,这时候钩子的执行顺序的问题凸显了出来。默认Mixin上会首先被注册,组件上的接着注册,这样我们就可以在组件中按需要重写Mixin中的语句。**组件拥有最终发言权。**当发生冲突并且这个组件就不得不“决定”哪个胜出的时候,这一点就显得特别重要,否则,所有的东西都被放在一个数组当中执行,Mixin将要被先推入数组,其次才是组件。

          //mixin
          const hi = {
          mounted() {
          console.log('hello from mixin!')
          }
          }
          //vue instance or component
          new Vue({
          el: '#app',
          mixins: [hi],
          mounted() {
          console.log('hello from Vue instance!')
          }
          });
          //Output in console
          > hello from mixin!
          > hello from Vue instance!
          

          如果这两个冲突了,我们看看 Vue实例或组件是如何决定输赢的:

          //mixin
          const hi = {
          methods: {
          sayHello: function() {
          console.log('hello from mixin!')
          }
          },
          mounted() {
          this.sayHello()
          }
          }
          //vue instance or component
          new Vue({
          el: '#app',
          mixins: [hi],
          methods: {
          sayHello: function() {
          console.log('hello from Vue instance!')
          }
          },
          mounted() {
          this.sayHello()
          }
          })
          // Output in console
          > hello from Vue instance!
          > hello from Vue instance!
          

          你可能已经注意到这有两个console.log而不是一个——这是因为第一个函数被调用时,没有被销毁,它只是被重写了。我们在这里调用了两次sayHello()函数。

          全局Mixin

          当我们使用“全局”来描述Mixin的时候,我们并不是说Mixin能够像filter,在每个组件都能被访问到。只是我们能够在组件通过mixins:[toggle]访问组件上的Mixin对象。

          全局Mixin被注册到了每个单一组件上。因此,它们的使用场景极其有限并且在使用的时候我们需要非常小心。一个我能想到的用途就是类似于插件,你需要赋予它访问所有东西的权限。但即使在这种情况下,我也对你正在做事情的充满警惕,尤其当你打算为应用增加通能的时候,这样做可能对你来说是个潘多拉的盒子。

          为了创建一个全局实例,我们可以把它放在Vue实例之上。在一个典型的 Vue-cli 初始化的项目中,它可能在你的main.js文件中。

          Vue.mixin({
          mounted() {
          console.log('hello from mixin!')
          }
          })
          new Vue({
          ...
          })
          

          再次提醒,小心使用它!那个console.log将会出现在每个组件上,在这个案例里还不算坏(除了控制台上有多余的输出)。但如果全局Mixin被错误的使用,你将能看到它有多可怕。

          结论

          Mixin对于封装一小段想要复用的代码来讲是有用的。对你来说Mixin当然不是唯一可行的选择:比如说高阶组件就允许你组合相似函数,Mixin只是的一种实现方式。我喜欢Mixin,因为我不需要传递状态,但是这种模式当然也可能会被滥用,所以,仔细思考下哪种选择对你的应用最有意义吧!

          Metadata

          Metadata

          Assignees

          No one assigned

            Labels

            框架&工具库Vue和React等前端框架或工具库相关

            Projects

            No projects

            Milestone

            No milestone

            Relationships

            None yet

            Development

            No branches or pull requests

            Issue actions

            , 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Vue-Mixin · Issue #10 · isNeilLin/note · GitHub
            Skip to content

            Vue-Mixin #10

            Description

            @isNeilLin

            在 Vue.js 中使用Mixin —— CSS-Tricks

            本文转载自:众成翻译
            译者:chechengpeng
            审校: betsey
            链接:http://www.zcfy.cc/article/3257
            原文:https://css-tricks.com/using-mixins-vue-js/?utm_campaign=Revue%20newsletter&utm_medium=Newsletter&utm_source=revue

            有一种很常见的情况:有两个非常相似的组件,他们的基本功能是一样的,但他们之间又存在着足够的差异性,此时的你就像是来到了一个分岔路口:我是把它拆分成两个不同的组件呢?还是保留为一个组件,然后通过props传值来创造差异性从而进行区分呢?

            两种解决方案都不够完美:如果拆分成两个组件,你就不得不冒着一旦功能变动就要在两个文件中更新代码的风险,这违背了 DRY 原则。反之,太多的props传值会很快变得混乱不堪,从而迫使维护者(即便这个人是你)在使用组件的时候必须理解一大段的上下文,拖慢写码速度。

            使用Mixin。Vue 中的Mixin对编写函数式风格的代码很有用,因为函数式编程就是通过减少移动的部分让代码更好理解(引自 Michael Feathers )。Mixin允许你封装一块在应用的其他组件中都可以使用的函数。如果使用姿势得当,他们不会改变函数作用域外部的任何东西,因此哪怕执行多次,只要是同样的输入你总是能得到一样的值,真的很强大!

            基础实例

            我们有一对不同的组件,它们的作用是通过切换状态(Boolean类型)来展示或者隐藏模态框或提示框。这些提示框和模态框除了功能相似以外,没有其他共同点:它们看起来不一样,用法不一样,但是逻辑一样。

            // 模态框constModal={template: '#modal',data(){return{isShowing: false}},methods: {toggleShow(){this.isShowing=!this.isShowing;}},components: {appChild: Child}}// 提示框constTooltip={template: '#tooltip',data(){return{isShowing: false}},methods: {toggleShow(){this.isShowing=!this.isShowing;}},components: {appChild: Child}}

            我们可以在这里提取逻辑并创建可以被重用的项:

            const toggle = {
            data() {
            return {
            isShowing: false
            }
            },
            methods: {
            toggleShow() {
            this.isShowing = !this.isShowing;
            }
            }
            }
            const Modal = {
            template: '#modal',
            mixins: [toggle],
            components: {
            appChild: Child
            }
            };
            const Tooltip = {
            template: '#tooltip',
            mixins: [toggle],
            components: {
            appChild: Child
            }
            };
            

            你可以点击这里,查看 Sarah Drasner(@sdras) 在CodePen上编写 Mixin 的例子

            为了更容易理解Mixin,这个例子故意编写得简单一些。真实应用中Mixin有如下的应用,但是它的作用也不仅限于此:获取视窗和组件的尺寸,采集特定的鼠标事件和图表的基本元素。Paul Pflugradt 有一个关于 Vue Mixins 的优秀项目,值得一提的是它是用 coffeescript 编写的。

            用法

            上面这个codepen的例子并没有告诉我们在一个真实的应用中如何使用Mixin,所以我们看看下面的这个。

            你可以按照你喜欢的任意方式设置你的目录结构,但为了结构规整我喜欢新建一个mixin目录。我们创建的这个文件含有.js扩展名(跟.vue相对,就像我们的其他文件),为了使用Mixin我们需要输出一个对象。

            directory structure shows mixins in a folder in components directory

            接着我们可以在Modal.vue使用这样的写法,来引入这个Mixin:

            import Child from './Child'
            import { toggle } from './mixins/toggle'
            export default {
            name: 'modal',
            mixins: [toggle],
            components: {
            appChild: Child
            }
            }
            

            即便我们使用的是一个对象而不是一个组件,生命周期函数对我们来说仍然是可用的,理解这点很重要。我们也可以这里使用mounted()钩子函数,它将被应用于组件的生命周期上。这种工作方式真的很灵活也很强大。

            合并

            在下面的这个例子,我们可以看到,我们不仅仅是实现了自己想要的功能,并且Mixin中的生命周期的钩子也同样是可用的。因此,当我们在组件上应用Mixin的时候,有可能组件与Mixin中都定义了相同的生命周期钩子,这时候钩子的执行顺序的问题凸显了出来。默认Mixin上会首先被注册,组件上的接着注册,这样我们就可以在组件中按需要重写Mixin中的语句。**组件拥有最终发言权。**当发生冲突并且这个组件就不得不“决定”哪个胜出的时候,这一点就显得特别重要,否则,所有的东西都被放在一个数组当中执行,Mixin将要被先推入数组,其次才是组件。

            //mixin
            const hi = {
            mounted() {
            console.log('hello from mixin!')
            }
            }
            //vue instance or component
            new Vue({
            el: '#app',
            mixins: [hi],
            mounted() {
            console.log('hello from Vue instance!')
            }
            });
            //Output in console
            > hello from mixin!
            > hello from Vue instance!
            

            如果这两个冲突了,我们看看 Vue实例或组件是如何决定输赢的:

            //mixin
            const hi = {
            methods: {
            sayHello: function() {
            console.log('hello from mixin!')
            }
            },
            mounted() {
            this.sayHello()
            }
            }
            //vue instance or component
            new Vue({
            el: '#app',
            mixins: [hi],
            methods: {
            sayHello: function() {
            console.log('hello from Vue instance!')
            }
            },
            mounted() {
            this.sayHello()
            }
            })
            // Output in console
            > hello from Vue instance!
            > hello from Vue instance!
            

            你可能已经注意到这有两个console.log而不是一个——这是因为第一个函数被调用时,没有被销毁,它只是被重写了。我们在这里调用了两次sayHello()函数。

            全局Mixin

            当我们使用“全局”来描述Mixin的时候,我们并不是说Mixin能够像filter,在每个组件都能被访问到。只是我们能够在组件通过mixins:[toggle]访问组件上的Mixin对象。

            全局Mixin被注册到了每个单一组件上。因此,它们的使用场景极其有限并且在使用的时候我们需要非常小心。一个我能想到的用途就是类似于插件,你需要赋予它访问所有东西的权限。但即使在这种情况下,我也对你正在做事情的充满警惕,尤其当你打算为应用增加通能的时候,这样做可能对你来说是个潘多拉的盒子。

            为了创建一个全局实例,我们可以把它放在Vue实例之上。在一个典型的 Vue-cli 初始化的项目中,它可能在你的main.js文件中。

            Vue.mixin({
            mounted() {
            console.log('hello from mixin!')
            }
            })
            new Vue({
            ...
            })
            

            再次提醒,小心使用它!那个console.log将会出现在每个组件上,在这个案例里还不算坏(除了控制台上有多余的输出)。但如果全局Mixin被错误的使用,你将能看到它有多可怕。

            结论

            Mixin对于封装一小段想要复用的代码来讲是有用的。对你来说Mixin当然不是唯一可行的选择:比如说高阶组件就允许你组合相似函数,Mixin只是的一种实现方式。我喜欢Mixin,因为我不需要传递状态,但是这种模式当然也可能会被滥用,所以,仔细思考下哪种选择对你的应用最有意义吧!

            Metadata

            Metadata

            Assignees

            No one assigned

              Labels

              框架&工具库Vue和React等前端框架或工具库相关

              Projects

              No projects

              Milestone

              No milestone

              Relationships

              None yet

              Development

              No branches or pull requests

              Issue actions

              , 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); Vue-Mixin · Issue #10 · isNeilLin/note · GitHub
              Skip to content

              Vue-Mixin #10

              Description

              @isNeilLin

              在 Vue.js 中使用Mixin —— CSS-Tricks

              本文转载自:众成翻译
              译者:chechengpeng
              审校: betsey
              链接:http://www.zcfy.cc/article/3257
              原文:https://css-tricks.com/using-mixins-vue-js/?utm_campaign=Revue%20newsletter&utm_medium=Newsletter&utm_source=revue

              有一种很常见的情况:有两个非常相似的组件,他们的基本功能是一样的,但他们之间又存在着足够的差异性,此时的你就像是来到了一个分岔路口:我是把它拆分成两个不同的组件呢?还是保留为一个组件,然后通过props传值来创造差异性从而进行区分呢?

              两种解决方案都不够完美:如果拆分成两个组件,你就不得不冒着一旦功能变动就要在两个文件中更新代码的风险,这违背了 DRY 原则。反之,太多的props传值会很快变得混乱不堪,从而迫使维护者(即便这个人是你)在使用组件的时候必须理解一大段的上下文,拖慢写码速度。

              使用Mixin。Vue 中的Mixin对编写函数式风格的代码很有用,因为函数式编程就是通过减少移动的部分让代码更好理解(引自 Michael Feathers )。Mixin允许你封装一块在应用的其他组件中都可以使用的函数。如果使用姿势得当,他们不会改变函数作用域外部的任何东西,因此哪怕执行多次,只要是同样的输入你总是能得到一样的值,真的很强大!

              基础实例

              我们有一对不同的组件,它们的作用是通过切换状态(Boolean类型)来展示或者隐藏模态框或提示框。这些提示框和模态框除了功能相似以外,没有其他共同点:它们看起来不一样,用法不一样,但是逻辑一样。

              // 模态框constModal={template: '#modal',data(){return{isShowing: false}},methods: {toggleShow(){this.isShowing=!this.isShowing;}},components: {appChild: Child}}// 提示框constTooltip={template: '#tooltip',data(){return{isShowing: false}},methods: {toggleShow(){this.isShowing=!this.isShowing;}},components: {appChild: Child}}

              我们可以在这里提取逻辑并创建可以被重用的项:

              const toggle = {
              data() {
              return {
              isShowing: false
              }
              },
              methods: {
              toggleShow() {
              this.isShowing = !this.isShowing;
              }
              }
              }
              const Modal = {
              template: '#modal',
              mixins: [toggle],
              components: {
              appChild: Child
              }
              };
              const Tooltip = {
              template: '#tooltip',
              mixins: [toggle],
              components: {
              appChild: Child
              }
              };
              

              你可以点击这里,查看 Sarah Drasner(@sdras) 在CodePen上编写 Mixin 的例子

              为了更容易理解Mixin,这个例子故意编写得简单一些。真实应用中Mixin有如下的应用,但是它的作用也不仅限于此:获取视窗和组件的尺寸,采集特定的鼠标事件和图表的基本元素。Paul Pflugradt 有一个关于 Vue Mixins 的优秀项目,值得一提的是它是用 coffeescript 编写的。

              用法

              上面这个codepen的例子并没有告诉我们在一个真实的应用中如何使用Mixin,所以我们看看下面的这个。

              你可以按照你喜欢的任意方式设置你的目录结构,但为了结构规整我喜欢新建一个mixin目录。我们创建的这个文件含有.js扩展名(跟.vue相对,就像我们的其他文件),为了使用Mixin我们需要输出一个对象。

              directory structure shows mixins in a folder in components directory

              接着我们可以在Modal.vue使用这样的写法,来引入这个Mixin:

              import Child from './Child'
              import { toggle } from './mixins/toggle'
              export default {
              name: 'modal',
              mixins: [toggle],
              components: {
              appChild: Child
              }
              }
              

              即便我们使用的是一个对象而不是一个组件,生命周期函数对我们来说仍然是可用的,理解这点很重要。我们也可以这里使用mounted()钩子函数,它将被应用于组件的生命周期上。这种工作方式真的很灵活也很强大。

              合并

              在下面的这个例子,我们可以看到,我们不仅仅是实现了自己想要的功能,并且Mixin中的生命周期的钩子也同样是可用的。因此,当我们在组件上应用Mixin的时候,有可能组件与Mixin中都定义了相同的生命周期钩子,这时候钩子的执行顺序的问题凸显了出来。默认Mixin上会首先被注册,组件上的接着注册,这样我们就可以在组件中按需要重写Mixin中的语句。**组件拥有最终发言权。**当发生冲突并且这个组件就不得不“决定”哪个胜出的时候,这一点就显得特别重要,否则,所有的东西都被放在一个数组当中执行,Mixin将要被先推入数组,其次才是组件。

              //mixin
              const hi = {
              mounted() {
              console.log('hello from mixin!')
              }
              }
              //vue instance or component
              new Vue({
              el: '#app',
              mixins: [hi],
              mounted() {
              console.log('hello from Vue instance!')
              }
              });
              //Output in console
              > hello from mixin!
              > hello from Vue instance!
              

              如果这两个冲突了,我们看看 Vue实例或组件是如何决定输赢的:

              //mixin
              const hi = {
              methods: {
              sayHello: function() {
              console.log('hello from mixin!')
              }
              },
              mounted() {
              this.sayHello()
              }
              }
              //vue instance or component
              new Vue({
              el: '#app',
              mixins: [hi],
              methods: {
              sayHello: function() {
              console.log('hello from Vue instance!')
              }
              },
              mounted() {
              this.sayHello()
              }
              })
              // Output in console
              > hello from Vue instance!
              > hello from Vue instance!
              

              你可能已经注意到这有两个console.log而不是一个——这是因为第一个函数被调用时,没有被销毁,它只是被重写了。我们在这里调用了两次sayHello()函数。

              全局Mixin

              当我们使用“全局”来描述Mixin的时候,我们并不是说Mixin能够像filter,在每个组件都能被访问到。只是我们能够在组件通过mixins:[toggle]访问组件上的Mixin对象。

              全局Mixin被注册到了每个单一组件上。因此,它们的使用场景极其有限并且在使用的时候我们需要非常小心。一个我能想到的用途就是类似于插件,你需要赋予它访问所有东西的权限。但即使在这种情况下,我也对你正在做事情的充满警惕,尤其当你打算为应用增加通能的时候,这样做可能对你来说是个潘多拉的盒子。

              为了创建一个全局实例,我们可以把它放在Vue实例之上。在一个典型的 Vue-cli 初始化的项目中,它可能在你的main.js文件中。

              Vue.mixin({
              mounted() {
              console.log('hello from mixin!')
              }
              })
              new Vue({
              ...
              })
              

              再次提醒,小心使用它!那个console.log将会出现在每个组件上,在这个案例里还不算坏(除了控制台上有多余的输出)。但如果全局Mixin被错误的使用,你将能看到它有多可怕。

              结论

              Mixin对于封装一小段想要复用的代码来讲是有用的。对你来说Mixin当然不是唯一可行的选择:比如说高阶组件就允许你组合相似函数,Mixin只是的一种实现方式。我喜欢Mixin,因为我不需要传递状态,但是这种模式当然也可能会被滥用,所以,仔细思考下哪种选择对你的应用最有意义吧!

              Metadata

              Metadata

              Assignees

              No one assigned

                Labels

                框架&工具库Vue和React等前端框架或工具库相关

                Projects

                No projects

                Milestone

                No milestone

                Relationships

                None yet

                Development

                No branches or pull requests

                Issue actions