Vue 中的无状态组件

更新日期: 2019-11-16阅读: 2.3k标签: 组件

啥是应用程序状态,为什么咱们需要它?

状态管理通常在较小的项目并不需要,但是当涉及到更大的范围时,如企业级的应用大部分需要它了。简单的说,状态是一个包含应用程序使用的最新值的对象。但是,如果咱们从结构的、更抽象的角度来看待它,就会清楚地看到,状态是复杂应该中重要一块,它使能够构建干净的体系结构,并将关注点强有力地分离开来。

通常,缺乏经验的开发人员无法预测对状态管理的需求,以及如何实现状态管理,因此很难了解状态管理的重要性。如果基于状态的组件堆积起来,它们之间的数据管理和共享将成为一场噩梦。从长远来看,拥有的基于状态的组件越多,出现的问题就越多。

如果没有使用外部包进行状态管理,那么最好尽可能少地使用基于状态的组件,而展示组件则使用围绕它们构建的状态。


vue 和无状态(函数)组件

Vue 中的无状态组件其实就是函数组件。但函数组件又是啥呢? 要回答这个问题,咱们首先必须理解什么是函数式编程。

与将程序分解为对象的面向对象方法不同,函数式编程鼓励将程序分解为小函数,这些小函数用于形成更高级的程序。我们创建的函数不依赖于或可以改变任何外部状态,这导致另一个观察结果,对于给定的输入,它们总是返回相同的输出。

因此,函数组件是没有状态的组件,并且可以更改它。函数组件输出总是基于给定的输入。在 Vue 方面,这类组件会根据给定的props给出不同的输出。

语法

Vue 提供了一种定义函数组件的简单方法。咱们只需要给个 functional 关键字就可以。在 2.5.0 及以上版本中,如果使用了单文件组件,那么基于模板的函数式组件可以这样声明::

<template functional>
  <div> 函数/无状态组件 </div>
</template>

或者

export default {
  functional: true,
  props: {
    // ...
  },
  render(createElement, context) {
    return createElement(
      'div', '函数/无状态组件'
    )
  }
}
注意:在 2.3.0 之前的版本中,如果一个函数式组件想要接收 prop,则 props 选项是必须的。在 2.3.0 或以上的版本中,你可以省略 props 选项,所有组件上的特性都会被自动隐式解析为 prop。

当使用函数式组件时,该引用将会是 htmlElement,因为他们是无状态的也是无实例的。

需要注意的是,传递给函数组件的惟一数据是props。这些组件是完全无状态的(没有响应数据),它们忽略传递给它们的任何状态,并且不触发任何生命周期方法(created、mounted等等)。

而且,咱们也不能通过使用 this 关键字来访问实例,因为这些组件也是不实例化的。相反,组件需要的所有东西都是通过context提供的。在render函数中,它作为createElement方法的第二个参数传递。

组件需要的一切都是通过 context 参数传递,它是一个包括如下字段的对象:

  • props:提供所有 prop 的对象
  • children: VNode 子节点的数组
  • slots: 一个函数,返回了包含所有插槽的对象
  • scopedSlots: (2.6.0+) 一个暴露传入的作用域插槽的对象。也以函数形式暴露普通插槽。
  • data:传递给组件的整个数据对象,作为 createElement 的第二个参数传入组件
  • parent:对父组件的引用
  • listeners: (2.3.0+) 一个包含了所有父组件为当前组件注册的事件监听器的对象。这是 data.on 的一个别名。
  • injections: (2.3.0+) 如果使用了 inject 选项,则该对象包含了应当被注入的属性。


为什么咱们需要无状态组件

到目前为止,咱们已经了解到函数组件是无状态的,在它们的核心中,它们只是可执行的函数,接受一些输入并根据其提供输出。

就它们的用法而言,因为函数式组件只是函数,所以渲染开销也低很多,这也意味着它们是非常高效的,不需要花太多时间渲染。同时,考虑高阶组件,它们不需要任何状态,它们所要做的就是用额外的逻辑或样式包装给定的子组件。

接下来,通例事例展示一样啥时使用函数组件,函数组件非常适合此类任务。


实例

在这个示例中,咱们创建一个panel组件,它充当一个包装器,并提供所需的样式。子组件将在panel 主体中渲染:

export default {
  name: 'panel',
  functional: true,
  props: {
    title: String
  },
  render(createElement, context) {
    const slots = context.slots();

    const header = createElement('header', {
      attrs: { class: 'panel-header'}
    }, context.props.title);
    
    const body = createElement('main', {
      attrs: { class: 'panel-body'}
    }, slots.default);

    return createElement('section', {
      attrs: { class: 'panel' }
    }, [header, body]);
  }
}

如上所述,此组件的唯一目的是提供类似于面板(卡片)的样式,它有header 和main元素,分别保存面板标题和HTML内容。整个过程是通过使用render函数中的createElement参数在中完成。createElement是 Vue 核心中实现的虚拟 dom 系统的一部分。

虚拟 DOM

Vue 通过建立一个虚拟 DOM 来追踪自己要如何改变真实 DOM。请仔细看这行代码

return createElement('h1', this.blogTitle)

createElement 到底会返回什么呢?其实不是一个实际的 DOM 元素。它更准确的名字可能是 createNodeDescription,因为它所包含的信息会告诉 Vue 页面上需要渲染什么样的节点,包括及其子节点的描述信息。我们把这样的节点描述为“虚拟节点 (virtual node)”,也常简写它为“VNode”。“虚拟 DOM”是我们对由 Vue 组件树建立起来的整个 VNode 树的称呼。

createElement 参数

接下来你需要熟悉的是如何在 createElement 函数中使用模板中的那些功能。这里是 createElement 接受的参数:

// @returns {VNode}
createElement(
  // {String | Object | Function}
  // 一个 HTML 标签名、组件选项对象,或者
  // resolve 了上述任何一种的一个 async 函数。必填项。
  'div',

  // {Object}
  // 一个与模板中属性对应的数据对象。可选。
  {
    // (详情见下一节)
  },

  // {String | Array}
  // 子级虚拟节点 (VNodes),由 `createElement()` 构建而成,
  // 也可以使用字符串来生成“文本虚拟节点”。可选。
  [
    '先写一些文字',
    createElement('h1', '一则头条'),
    createElement(MyComponent, {
      props: {
        someProp: 'foobar'
      }
    })
  ]
)

面板 css 样式如下:

.panel {
  margin-bottom: .5rem
}

.panel, .panel-header {
    border: 1px solid #d3d3d3;
    border-radius: 4px;
}

.panel-header, .panel-body, .panel {
  padding: .5rem;
}

.panel-header {
  background-color:#efefef;
  color: #eeeee
}

这是一个简单直接的 CSS,提供了一些padding 和color。

子组件

现在,为了让例子更加生动为此,咱们再创建两个附加组件,一个显示汽车列表,另一个只是一个简单lorem-ipsum的文本组件,要求它们具有相同的面板样式和外观。

列表组件:

export default {
  name: 'cars',
  props: {
    data: Array
  }
}

template:

<template>
  <ul>
    <li v-for="car in data" :key="car">{{car}}</li>
  </ul>
</template>

文本组件:

export default {
  name: 'lorem-ipsum'
}

template:

<template>
  <p>
   终身学习者,终身学习者,终身学习者,终身学习者,终身学习者
  </p>
</template>

现在,有了可用的子组件,咱们所需要做的就是用panel组件将它们封装到应用程序中,如下所示:

<div class="vue-app">
  <panel :title="'Car Manufacturers'">
    <cars :data="['Mazda', 'Ford', 'Mercedes']"></cars>
  </panel>
  <panel :title="'Lorem Ipsum'">
    <lorem-ipsum></lorem-ipsum>
  </panel>
</div>
请注意,使用这些组件是因为示例比较简单。在实际应用中,它可以是任何类型的组件。


完整代码

hmtl

<div class="vue-app">
  <panel :title="'Car Manufacturers'">
    <cars :data="['Mazda', 'Ford', 'Mercedes']"></cars>
  </panel>
  <panel :title="'Lorem Ipsum'">
    <lorem-ipsum></lorem-ipsum>
  </panel>
</div>

<script type="text/x-template" id="cars">
  <template>
    <ul>
      <li v-for="car in data" :key="car">{{car}}</li>
    </ul>
  </template>
</script>

<script type="text/x-template" id="lorem-ipsum">
  <template>
    <p>前端小智, 终身学习者,终身学习者,终身学习者,终身学习者,终身学习者</p>
  </template>
</script>

css

body {
  padding: .5rem
}

* {
  padding: 0;
  margin:0;
  box-sizing: border-box;
}

.panel {
  margin-bottom: .5rem
}

.panel, .panel-header {
    border: 1px solid #d3d3d3;
    border-radius: 4px;
}

.panel-header, .panel-body, .panel {
  padding: .5rem;
}

.panel-header {
  background-color:#efefef;
  color: #eeeee
}

ul {
  list-style: none;
}

ul > li {
  padding: .5rem .2rem
}

js

// the wrapper panel
const panel = {
  functional: true,
  name: "panel",
  props: {
    title: String
  },
  render(createElement, context) {
    const slots = context.slots();

    const header = createElement('header', {
      attrs: { class: 'panel-header'}
    }, context.props.title);
    
    const body = createElement('main', {
      attrs: { class: 'panel-body'}
    }, slots.default);

    return createElement('section', {
      attrs: { class: 'panel' }
    }, [header, body]);
  }
}

// sample components

const cars = {
  name: 'cars',
  template: '#cars',
  props: {
    data: Array
  }
}

const loremIpsum = {
  name: 'lorem-ipsum',
  template: '#lorem-ipsum'
}

new Vue({
  el: '.vue-app',
  components: {
    panel,
    cars,
    'lorem-ipsum': loremIpsum
  }
});

原文:https://itnext.io/


链接: https://fly63.com/article/detial/7455

Vuetify基于vue2.0,为移动而生的组件框架

Vuetify 支持SSR(服务端渲染),SPA(单页应用程序),PWA(渐进式Web应用程序)和标准HTML页面。 Vuetify是一个渐进式的框架,试图推动前端开发发展到一个新的水平。

Vue中插槽的作用_Vue组件插槽的使用以及调用组件内的方法

通过给组件传递参数, 可以让组件变得更加可扩展, 组件内使用props接收参数,slot的使用就像它的名字一样, 在组件内定义一块空间。在组件外, 我们可以往插槽里填入任何元素。slot-scope的作用就是把组件内的数据带出来

react 函数子组件(Function ad Child Component)

函数子组件(FaCC )与高阶组件做的事情很相似, 都是对原来的组件进行了加强,类似装饰者。FaCC,利用了react中children可以是任何元素,包括函数的特性,那么到底是如何进行增强呢?

Vue和React组件之间的传值方式

在现代的三大框架中,其中两个Vue和React框架,组件间传值方式有哪些?组件间的传值是灵活的,可以有多种途径,父子组件同样可以使用EventBus,Vuex或者Redux

vue.js自定义组件directives

自定义指令:以v开头,如:v-mybind。bind的作用是定义一个在绑定时执行一次的初始化动作,观察bind函数,它将指令绑定的DOM作为一个参数,在函数体中,直接操作DOM节点为input赋值。

vue中prop属性传值解析

prop的定义:在没有状态管理机制的时候,prop属性是组件之间主要的通信方式,prop属性其实是一个对象,在这个对象里可以定义一些数据,而这些数据可以通过父组件传递给子组件。 prop属性中可以定义属性的类型,也可以定义属性的初始值。

Web组件简介

Web组件由三个独立的技术组成:自定义元素。很简单,这些是完全有效的HTML元素,包含使用一组JavaScript API制作的自定义模板,行为和标记名称(例如,<one-dialog>)。

web组件调用其他web资源

web组件可以直接或间接的调用其他web资源。一个web组件通过内嵌返回客户端内容的另一个web资源的url来间接调用其他web资源。在执行时,一个web资源通过包含另一个资源的内容或者转发请求到另一个资源直接调用。

vue中如何实现的自定义按钮

在实际开发项目中,有时我们会用到自定义按钮;因为一个项目中,众多的页面,为了统一风格,我们会重复用到很多相同或相似的按钮,这时候,自定义按钮组件就派上了大用场,我们把定义好的按钮组件导出,在全局引用,就可以在其他组件随意使用啦,这样可以大幅度的提高我们的工作效率。

Vue子组件调用父组件的方法

Vue中子组件调用父组件的方法,这里有三种方法提供参考,第一种方法是直接在子组件中通过this.$parent.event来调用父组件的方法,第二种方法是在子组件里用$emit向父组件触发一个事件,父组件监听这个事件就行了。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!