如果只有一天,如何学习vuejs?

1. 树靶:从入门到精通?

伴随着计算机技术的发展,我们总是能听到或看到《n天从入门到精通》系列丛书,精通一词总能给人带来一阵兴奋,好像找到了武功秘籍,练后就登峰造极。

但这多半只是换来脑中一热,只是精通招式,还是不能为我所用创造出令自己满意的效果。

这篇文章必然不属于该系列,”一天”这个限制并不想蒙蔽读者,而只是为了创造一个极限条件,时间有限不能全部照顾到,逼迫我们去思考什么才是最重要的。

打蛇打七寸,当真屡试不爽。但是每个人都有自己的学习方式,并不一定对所有人都有效。不以为然者尽可以把这当作另一种思路借鉴。

下面我们就来看看,一天时间,能把哪些重要的东西学到手。

2. 探路:我眼中的vuejs是怎样的?

首先,我要做些铺垫,来说明一下我眼中的vuejs是个什么工具,用以解决什么问题。

计算机语言发展史,在我看来就是一个抽象层次不断升级的历史。

最开始的面向过程编程,比如c语言,实际上是将功能逻辑封闭到了函数,是对过程的抽象。这是第一层。

但是过程虽然做了抽象,数据却还是游离在代码中,面向对象编程即是再将数据跟逻辑一起封装为一个整体,即对象。这是第二层。

这两者都是代码层面,复用程度也还是有限。于是出现了一些第三方模块,复用程度较面向对象又高了一个层次。这是第三层。

再上一层就涉及到具体功能设计了,比如django的contrib.admin,即是django将整个功能以插件方式使用的极好例子,这些代码已可以完整提供功能模块了。这是第四层。

当然,上面还有更高明的设计,IaaS、SaaS、PaaS更是提供了整个运行时的能力,直接申请运行时即可使用,简单方便,程度又高了一层。这是第五层。

vuejs的设计介于第三层和第四层之间,虽说提供了某种层次的抽象,类似第三方模块,但是它更提供了抽象的解决方案。这正是它跟jQuery这类 js库 的差别所在。

更具体得说,vuejs实现了一个叫做component的前端复用粒度,并提供了一整套框架来使component足够灵活以满足绝大多数需求。

我们下面便来看一下vuejs中的component是如何达到抽象复用的。

3. 观详:vuejs中的component设计

这里的标题是component设计,而不是”component如何编写”,如何编写并不十分重要,我们想要知道的是,它是怎么设计来满足我们目标的。

为什么是它满足我们的目标而不是我们去学习它的使用?因为我们的思考是第一位的,否则很容易在这纷繁的世界中迷失,人云易云。

那我们就先设计一个框架,让vuejs实现这个框架(奇怪,竟然是vuejs来贴合我们的思考,而不是我们去学习了)。

那我们现在就来思考,如何设计一个可以复用的component,满足我们复用的需求。

。。。

经过了几分钟的思考,我认为一个可复用的组件,要满足以下几个条件:

  • 属性:我们可以利用属性来定义一个组件的外观,或者交互方式
  • 输出:component不光好看(或不好看),可能还能输出某种状态或数据,比如一个获取输入的组件,我们需要从组件中获取输入的内容
  • 控制:component需要提供一些对外接口,以便我们对它进行控制
  • 感知:有时component需要主动将自己的内部状态通知出来。跟被动控制不同的是,感知是component主动通知外部的行为

现在,我们只需要拿着这份药方去vuejs抓药就可以了。下面是我们找到的药品的位置:

  • 属性:vuejs中明显地提供了属性的定义及访问方式,component中使用 props 来指定其支持哪些属性,使用方可以通过 :prop="config.prop" 传入属性
  • 输出:输出的实现有些技巧,后面我们专列一个小节来说明
  • 控制:想要控制某个component,必先获取它对应的句柄(与之对应的某个变量)。vuejs为组件的使用提供了一个 ref 属性,可通过 this.refs 变量引用到,直接调用其函数
  • 感知:主动通知的实现方式,一般为信号(linux进程)和事件(js),但本质是相同的,都是底层提供一种通信方式。vuejs提供了 $emit() 函数,用以向component使用方发送通知

4. 试剑:不跑起来不算验收通过

上面的实现描述不够直观,还是要看到代码才能更清楚明白。下面我们就创建一个项目来验证上面的设计。

这里我们先编写一个简单的用例,一个用以显示文本的component,同时可通过一个api来修改字体大小。

我们先安装vue命令行工具,并用其创建一个脚手架项目:

script
1
2
npm install -g @vue/cli
vue create component-demo

然后我们创建一个component,该component可定义显示一行文本,可通过一个属性来设置文本颜色。同时,我们提供两个接口以供使用方调整字体大小。

先看使用方的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!-- src/App.vue -->
<Label color="green" text="hello" ref="label1" />
<button @click="enlarge">enlarge</button>
<button @click="diminish">diminish</button>

<script>
export default {
name: 'App',
components: {
Label
},
methods: {
enlarge() {
this.$refs.label1.enlarge()
},
diminish() {
this.$refs.label1.diminish()
}
}
}
</script>

下面是component的定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!-- src/components/Label.vue -->
<template>
<span :style="{color: color, 'font-size': fontSize + 'px'}">{{ text }}</span>
</template>

<script>
export default {
name: 'Label',
props: ['color', 'text'],
data() {
return {
fontSize: 18
}
},
methods: {
enlarge() {
this.fontSize += 1
},
diminish() {
this.fontSize -= 1
}
}
}
</script>

5. 转锋:同步数据给父component

上面的组件已可以很好的工作了,但是它并没有覆盖到我们上面给出的四个条件,我对比了一下,缺少 输出感知 两个条件,这两个条件实现的技术实际是同一个。

vuejs提供了一种通信方式,可以向父component发送数据,原型为 $emit( eventName, […args] ),eventName为事件名,是一个字符串,可为该事件提供参数 args。

如果我们是直接看vuejs的官方教程,官方指出v-model可以实现数据的双向绑定(数据显示<=>数据变量这两个方向)。官方也给出了v-model背后的诀窍:

你可以用 v-model 指令在表单 input、textarea 及 select 元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但 v-model 本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。

text 和 textarea 元素使用 value property 和 input 事件;

下面的代码更直白一些:

1
2
3
4
<input type="text" v-model="data">

<!--等同于下面的代码-->
<input type="text" v-bind="data" v-on:input="data = $event.target.value" />

即是如此,我们便可以通过包装一个input,并给上层上送input事件来通知上层更新数据了。下面是一个片段:

1
2
3
4
5
6
7
<!--父component-->
<InputComponent v-model="data" />

<!--子component-->
<input>
<input v-bind="data" v-on:input="$emit('input', data)">
</template>

当然,框架里还提供了一个model属性,可以修改v-model绑定的属性(这里默认为value)和事件(这里默认为input)。这算是个彩蛋了。

如果要更细致的使用,还需要了解一下生命周期的概念,不过这对于使用来说并不是最核心最要紧的。

6. 回首:再来看n天精通系列

我相信n天精通是存在的,但是这不是必然的。比起精通,能够产生有实际价值的产品,才是更令人兴奋的。

所以,n天能精通也罢,不能精通也罢,并不是那么重要。

网上看到一个朋友的说法,我觉得说得挺好:工具是帮助我们解决问题的,而不是让人成为大牛的。

精通和有效,必然有先后。我觉得大可先让学习有效,真正到了一定程度,自然便精通了。

有了上面的学习,我们就可以触类旁通,继续学习相关知识,一边学习、一边享受学习的成果,不也是一件很快乐的事吗?