vue

Vue中组件的设计

Vue 中组件设计经常遇到复合组件的问题,例如下拉菜单,下拉菜单中我们不仅要实现select元素的功能,还要实现option元素的功能,这样才是一个完整的下拉菜单组件。

# 复合组件中的数据相互访问

复合组件中的数据访问是设计组件的一个重要议题,设计不好会严重影响组件的灵活性。我们拿 Element UI 的组件来举个例子:

<el-select v-model="value" placeholder="请选择">
  <el-option
    v-for="item in options"
    :key="item.value"
    :label="item.label"
    :value="item.value"
  >
  </el-option>
</el-select>
1
2
3
4
5
6
7
8
9

这是一个经典的例子,但是实际使用过程中,我们可能会二次封装组件,例如我们需要给el-option加一些事件或者样式,那我们的代码会变成这样:

<el-select v-model="value" placeholder="请选择">
  <styled-el-option
    v-for="item in options"
    :key="item.value"
    :label="item.label"
    :value="item.value"
  >
  </styled-el-option>
</el-select>
1
2
3
4
5
6
7
8
9

styled-el-option 是我们二次封装的组件,里面包含了el-option组件。如果我们使用$parentel-option组件中访问el-select组件的话,二次封装的情况下就会出错。 因为el-option的父组件不再是el-select,而是styled-el-option。正确的数据访问方式是使用provideinject

# 子组件访问父组件

首先我们需要在父附件中这样定义:

provide: function () {
  return {
    'select': this
  }
}
1
2
3
4
5

然后在子组件中使用inject:

inject: ['select']
1

这样子组件就可以访问父组件了,使用provide的好处是不用担心复合组件中的再封装问题,Vue 会自动向上查找。

# 父组件访问子组件

Vue 中并没有提供非常方便的查找子组件的功能, 所以目前的方法是在父组件中存储子组件的实例。

父组件中定义数据:

data: function () {
  return {
    options: []
  }
}
1
2
3
4
5

子组件通过inject可以访问父组件,所以:

  created() {
    this.select.options.push(this);
  }
1
2
3

在创建组件的时候同时传入父组件的data字段中。

# 总结

灵活的设计组件才能在实际开发中更方便的使用,一些第三方组件开发的时候没有考虑到二次封装的可能性,直接通过$parent$children进行数据的更新。导致可用性大大降低。

# 参考

Dependency Injection (opens new window)

Vue实现双Slider

前端由于历史原因,基本上没有组件的概念,原生的 HTML 元素提供的功能非常简陋,所以都需要开发者自己实现或者定制组件。这次讲讲双 Slider 的实现。

# 技术选型

目前比较流行的 Vue 的组件库是Element (opens new window)View UI (opens new window)。这两个组件库都使用了最常用的方法,使用div或者span,元素模拟滑动条,监听事件,并处理滑动。但是 HTML 元素本身提供了Range (opens new window)标签,我们可以修改下样式来使用,这样就避免自己直接处理事件监听,也可以减少浏览器兼容性问题。

# 样式定制化

目前针对 Range 元素的样式定制化还没有纳入 Web 标准,所以在处理起来稍微花点功夫。首先,我们需要修改默认的滑块样式。使用的 CSS 选择器是-webkit-slider-thumb (opens new window)。由于未纳入标准,需要使用浏览器前缀才行。这里我们可以借助 postcss-input-range (opens new window) 插件来完成这项工作。

# 双 Slider 实现

HTML 本身只提供了单滑块,要想实现双 Slider,只能两个叠加在一起了,并且需要自己实现 Slider 的选中范围,因为目前的 css selector 并不能达到这种效果。如何动态的控制 Slider 的显示长度呢?当然可以计算出目前的选中百分比,通过 css variables 来达到更新样式的效果。

# Slider 滑动规则

当然,我们左边的滑块不能滑过右边的滑块,这是基本常识。这里就需要监听input 事件,当超出范围的时候,强制把值重置回合法值就可以了。

# 实现效果

# 总结

能用原生 HTML 标签来解决的问题,尽量还是不要自己实现事件监听了。这样性能也会更好,兼容性上也不会太差。

Vue表单组件如何自动化输入

使用 Vue 的数据双向绑定功能可以很方便的完成表单的数据收集和提交,再也不用自己手动监听事件和收集数据了。但同时自动化输入也变得复杂起来。

# 传统表单自动化输入

对于传统的表单我们可以很简单的自动化输入过程,例如checkboxinput元素,我们可以自动选中和输入内容:

document.querySelector('.checkbox').checked = true;
document.querySelector('.input').value = true;
1
2

当用户提交的时候,程序会读取相应元素的值,然后填充到请求里。

# Vue 组件自动化输入

这里我们以现在流行的Element (opens new window)为例子演示如何自动化输入。用过 Vue 的人都知道, v-model是用来进行双向绑定的。它的原理是:

Vue.component('custom-input', {
  props: ['value'],
  template: `
    <input
      v-bind:value="value"
      v-on:input="$emit('input', $event.target.value)"
    >
  `
});
1
2
3
4
5
6
7
8
9

到这里,我们就知道了通过$emit('input', value)的方式,可以绑定想要输入的值,直接使用传统方式修改input元素的值,有时候不会触发input事件,所以不是一个可行的办法。

接下来,我们讲下如何选中元素并调用$emit,例子是 Vue 官网的搜索框 (opens new window)

const input = document.querySelector('.el-input');
input.__vue__.$emit('input', 'Hello world');
1
2

console里输入这两行代码,你会发现搜索框里被填入了Hello World。Vue 实例被隐藏到了 DOM 中,只要知道如何访问 Vue 然好调用$emit,问题就迎刃而解。

# 总结

现在的前端框架用起来方便,但也隐藏了大量细节。导致做自动化的时候不知道如何下手,尝试修改元素的值,但发现提交的时候还是没有带上正确的数值。这时候就需要思考框架绑定数据的本质是什么, 弄清了本质,其实做起来发现更简单!