Vue常用模式

Vue常用模式

组件定义

SFC 单文件组件

SFC






字符串模板或 ES6 模板字面量

Vue.component('my-btn', { template: `

`, data() { return { count: 0, }; }, methods: { handleClick() { this.count++;
console.log('clicked', this.count); }, }, });

渲染函数

Vue.component('my-btn', { data() { return { count: 0, }; }, methods: {
handleClick() { this.count++; console.log('clicked', this.count); }, },
render(h) { return h( 'button', { attrs: { class: 'btn-primary', }, on: { click:
this.handleClick, }, }, this.$slots.default ); }, });

JSX 语法糖

Vue.component('my-btn', { data() { return { text: 'Click me', }; }, methods: {
handleClick() { console.log('clicked'); }, }, render() { return (

); }, });

Vue 类组件装饰器






参考

  • https://vuejs.org/v2/guide/single-file-components.html
  • https://vuejs.org/v2/guide/render-function.html
  • https://medium.com/js-dojo/7-ways-to-define-a-component-template-in-vuejs-c04e0c72900d
  • https://codewithhugo.com/writing-multiple-vue-components-in-a-single-file/

组件通信

Prop属性和事件

vue组件基本上遵循单向数据流原则,即数据通过props向下传递子组件,子组件向上触发事件。

props数据只读,因此无法子组件无法改变props。 当props变化时,子组件会自动重新渲染。(props是响应式数据源)

子组件只能向父组件触发事件,父组件接收事件,改变映射至子组件的props数据。







参考

https://vuejs.org/v2/guide/components-props.html
https://alligator.io/vuejs/component-communication/
https://www.smashingmagazine.com/2017/08/creating-custom-inputs-vue-js/
https://vegibit.com/vue-sibling-component-communication/
https://medium.com/fullstackio/managing-state-in-vue-js-23a0352b1c87
https://gambardella.info/2017/09/13/vue-js-communication-part-2-parent-child-components/

组件事件处理

参考

  • https://vuejs.org/v2/guide/components-custom-events.html
  • https://itnext.io/leveraging-vue-events-to-reduce-prop-declarations-e38f5dce2aaf
  • https://alligator.io/vuejs/component-event-hooks/
  • https://alligator.io/vuejs/global-event-bus/
  • https://medium.com/@jesusgalvan/vue-js-event-bus-promises-f83e73a81d72

组件条件渲染

指令

v-if

Render only if v-if condition is true

v-ifv-else

Render only if v-if condition is true

Render only if v-if condition is false

v-else-if

Render only if `type` is equal to `A`
Render only if `type` is equal to `B`
Render only if `type` is equal to `C`
Render if `type` is not `A` or `B` or `C`

v-show

Always rendered, but it should be visible only if `v-show` conditions is true

如果想条件渲染多个元素,可以在模板template元素上使用条件指令。

注意模板元素仅仅是隐形包装,不会渲染成DOM。


渲染函数或JSX语法糖

如果你在vue应用中使用渲染函数或jsx, 可以直接使用 if-elseswitch-case语句以及三元和逻辑运算符。

if-else语句

export default {
  data() {
    return {
      isTruthy: true,
    };
  },
  render(h) {
    if (this.isTruthy) {
      return 

Render value is true

; } else { return

Render value is false

; } }, };

switch case语句

import Info from './Info';
import Warning from './Warning';
import Error from './Error';
import Success from './Success';

export default {
  data() {
    return {
      type: 'error',
    };
  },
  render(h) {
    switch (this.type) {
      case 'info':
        return ;
      case 'warning':
        return ;
      case 'error':
        return ;
      default:
        return ;
    }
  },
};

或者你可以使用map对象简化switch-case

import Info from './Info';
import Warning from './Warning';
import Error from './Error';
import Success from './Success';

const COMPONENT_MAP = {
  info: Info,
  warning: Warning,
  error: Error,
  success: Success,
};

export default {
  data() {
    return {
      type: 'error',
    };
  },
  render(h) {
    const Comp = COMPONENT_MAP[this.type || 'success'];

    return ;
  },
};

三元运算符

export default {
  data() {
    return {
      isTruthy: true,
    };
  },
  render(h) {
    return (
      
{this.isTruthy ? (

Render value is true

) : (

Render value is false

)}
); }, };

逻辑运算符

export default {
  data() {
    return {
      isLoading: true,
    };
  },
  render(h) {
    return 
{this.isLoading &&

Loading ...

}
; }, };

参考

https://vuejs.org/v2/guide/conditional.html
https://dzone.com/articles/difference-between-v-if-and-v-show-with-a-video

动态组件

带有is属性组件


上例中,如果有不同组件渲染进入component组件,渲染过的组件将会销毁。

如果你想要component标签内部实例不被销毁,可以在外面再包一层keep-alive

  

参考

https://vuejs.org/v2/guide/components.html#Dynamic-Components
https://vuejs.org/v2/guide/components-dynamic-async.html
https://medium.com/scrumpy/dynamic-component-templates-with-vue-js-d9236ab183bb

组件组合

第三方库

Proppy-组件函数式组合方案

基础组合




参考

https://vuejs.org/v2/guide/#Composing-with-Components

扩展

当你想扩展单文件组件时可以使用扩展:




参考

https://vuejs.org/v2/api/#extends
https://medium.com/js-dojo/extending-vuejs-components-42fefefc688b

混入

// closableMixin.js
export default {
  props: {
    isOpen: {
      default: true,
    },
  },
  data: function() {
    return {
      shown: this.isOpen,
    };
  },
  methods: {
    hide: function() {
      this.shown = false;
    },
    show: function() {
      this.shown = true;
    },
    toggle: function() {
      this.shown = !this.shown;
    },
  },
};



参考

https://vuejs.org/v2/guide/mixins.html
http://www.qcode.in/practical-use-of-components-and-mixins-in-vue-js/

默认插槽

/* VBtn */






参考

https://vuejs.org/v2/guide/components-slots.html#Slot-Content
https://alligator.io/vuejs/component-slots/
https://alligator.io/web-components/composing-slots-named-slots/
https://alligator.io/vuejs/vue-abstract-components/

命名插槽

基础布局文件

/* base-layout */

应用文件


  

  

A paragraph for the main content.

And another one.

参考

https://vuejs.org/v2/guide/components-slots.html#Named-Slots
https://medium.com/@fdietz/vue-js-component-composition-with-slots-eda311579218

域插槽







参考

https://vuejs.org/v2/guide/components-slots.html#Scoped-Slots
https://medium.com/js-dojo/getting-your-head-around-vue-js-scoped-slots-281bf82a1e4e
https://medium.com/corebuild-software/understanding-scoped-slots-in-vue-js-db5315a42391
https://alligator.io/vuejs/scoped-component-slots/
https://adamwathan.me/the-trick-to-understanding-scoped-slots-in-vuejs/
https://pineco.de/power-scoped-slots-vue/
https://medium.com/@tkwebdev/building-a-list-keyboard-control-component-with-vue-js-and-scoped-slots-c74db4fcf84f

渲染属性

大部分场景可以用域插槽替代渲染属性,但有些场景渲染属性更有用。

使用SFC





使用JSX

const Mouse = {
  name: 'Mouse',
  props: {
    render: {
      type: Function,
      required: true,
    },
  },
  data() {
    return {
      x: 0,
      y: 0,
    };
  },
  methods: {
    handleMouseMove(event) {
      this.x = event.clientX;
      this.y = event.clientY;
    },
  },
  render(h) {
    return (
      
{this.$props.render(this)}
); }, }; export default Mouse;

参考

https://vuejs.org/v2/guide/render-function.html
https://medium.com/@dillonchanis/leveraging-render-props-in-vue-7eb9a19c262d
https://medium.com/js-dojo/use-a-vue-js-render-prop-98880bc44e05
https://medium.com/js-dojo/using-react-style-callback-props-with-vue-pros-and-cons-e0ee7455695b

传递 Props 和监听器

有时需要向子组件传递属性和监听器,但不需要声明全部属性。

你可以在子组件中绑定$attrs$listeners,设置inheritAttrsfalse

外部div和子组件都会接收到设置的attributes。

传递Props




父组件




参考

https://zendev.com/2018/05/31/transparent-wrapper-components-in-vue.html

高阶组件

参考

  • https://medium.com/bethink-pl/higher-order-components-in-vue-js-a79951ac9176
  • https://medium.com/bethink-pl/do-we-need-higher-order-components-in-vue-js-87c0aa608f48
  • https://medium.com/tldr-tech/higher-order-components-in-vue-js-38b500c6d49f

依赖注入

Vue支持 Provide和Inject机制为所有子代组件提供对象。

不管组件层次有多深,只要都在共同父组件下,机制都可以发挥作用。

注意provideinject绑定都不是响应式的,除非传递可观察对象。


  
    
  

根据上例中组件层次,为了从父组件中获取数据,你应该将数据对象作为props传递给
子组件和孙组件。但是如果父组件提供数据对象,孙组件仅定义注入父组件提供的数据对象可以直接获取数据。

参考

  • https://vuejs.org/v2/api/#provide-inject
  • https://vuejs.org/v2/guide/components-edge-cases.html#Dependency-Injection
  • https://alligator.io/vuejs/component-communication/#provide--inject
  • https://blog.kloud.com.au/2017/03/22/dependency-injection-in-vuejs-app-with-typescript/

Provide和Inject API

提示: 可以使用vue属性装饰器的@Provide@Inject

主题提供者


带主题按钮





  

Themed Button

错误处理

errorCaptured 钩子函数

错误边界


抛出错误




  

参考

  • https://medium.com/@dillonchanis/handling-errors-in-vue-with-error-boundaries-91f6ead0093b
  • https://jsfiddle.net/Linusborg/z84wspcg/

效率建议

创建时执行观察

// don't
created() {
  this.fetchUserList();
},
watch: {
  searchText: 'fetchUserList',
}
// do
watch: {
  searchText: {
    handler: 'fetchUserList',
    immediate: true,
  }
}

译者注

  • 原文链接
  • vue 技术内幕
  • 原文有删减,因译者水平有限,如有错误,欢迎留言指正交流

你可能感兴趣的:(Vue常用模式)