如何实现一个简版的Vuex

如何实现一个最简单的Vuex

要自己实现一个mini版的Vuex,当然要先了解他(Vuex)的原理。以及他都做了些什么?

Vuex的实现原理

先来看看Vuex官网对自己的介绍:

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

那么本文中的mini版Vuex会简单实现一些Vuex的基础功能:

  • 像真正的Vuex一样编写和引用
  • 实现Vuex的state,getter,mutations,actions(仅基础实现)

1. 提前扫盲,每次我们要引入Vuex都要使用以下代码来安装,

1
2
3
4
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

官方文档的解释:

安装 Vue.js 插件。如果插件是一个对象,必须提供 install 方法。如果插件是一个函数,它会被作为 install 方法。install 方法调用时,会将 Vue 作为参数传入。

Vue.use()会执行传入对象的install方法(或者你直接向外暴露的install函数),以此安装插件

所以,想要我们的Vuex能够像官方的写法一致,除了提供类似的构造函数,还需要提供install方法。

2. 编写Vuex类,以及他的构造函数

新建一个my-vuex.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
let Vue; // 通过插件传递进来的Vue对象

//创建Vuex类
class Store{

//构造函数
constructor(options) {

// 将传入的options挂载到Store类上

//使用一个Vue对象保存state中的值
this.state = new Vue({
data: options.state
})

// {mutations: {add:function(state){}}}
this.mutations = options.mutations || {};

// {actions: {add:function(ctx){}}}
this.actions = options.actions || {};

this.handleGetters(options.getters);

this.$options = options;

}
}

3. 编写Vuex的install静态方法

使用Vue.mixin()将store对象绑定到Vue的原型链上

关于混入

1
2
3
4
5
6
7
8
9
10
11
12
13
//提供install方法
function install (_Vue) {
Vue = _Vue;

Vue.mixin({
beforeCreate() {
if (this.$options.store) {
Vue.prototype.$store = this.$options.store
}
}
})
}
export default {Store,install}

4. handleGetters方法

1
2
3
4
5
6
7
8
9
10
handleGetters(getters) {
this.getters = {};
Object.keys(getters).forEach(key => {
Object.defineProperty(this.getters, key, {
get: () => {
return getters[key](this.state)
}
})
})
}

5. commit,dispatch方法

解析option中的router

1
2
3
4
5
6
7
8
9
10
11
12
commit = (type, arg) => {
this.mutations[type](this.state, arg)
}

dispatch = (type, arg) => {

this.actions[type]({
commit: this.commit,
state: this.state,
getters: this.getters
}, arg)
}

6. 完整Store类结构一览

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
let Vue;

class Store {

constructor(options) {
this.state = new Vue({
data: options.state
})
this.mutations = options.mutations || {};
this.actions = options.actions || {};
this.handleGetters(options.getters);
}

commit = (type, arg) => {
this.mutations[type](this.state, arg)
}

dispatch = (type, arg) => {
this.actions[type]({
commit: this.commit,
state: this.state,
getters: this.getters
}, arg)
}

handleGetters(getters) {
this.getters = {};
Object.keys(getters).forEach(key => {
Object.defineProperty(this.getters, key, {
get: () => {
return getters[key](this.state)
}
})
})
}
}
function install (_Vue) {
Vue = _Vue;

Vue.mixin({
beforeCreate() {
if (this.$options.store) {
Vue.prototype.$store = this.$options.store
}
}
})
}
export default {Store,install}

结尾

因为这是一个mini版本的Vuex,非常简陋,仅仅实现了最基础的几个功能。

关键代码片段github地址

(转载)'风险是可控的,只是需要高度自律'

转载文章:高手是怎样炼成的?

原文链接

摘要

纪录片《徒手攀岩》中,Alex 徒手没有任何保护,爬上了酋长岩。即使是在专业的攀岩运动员看来,这也是一个不可能完成的任务。说白了,就等于送死。

他说了一句话,非常地奇怪,他说:”风险和后果是两回事。徒手攀岩的风险很低,只是后果很严重。”

正文


和你一起终身学习,这里是罗辑思维。

今年的奥斯卡最佳纪录片奖,颁给了一部纪录片,叫做《徒手攀岩》。我早就知道这部片子的大名,但是最近才有时间把它看了。看完之后,给了我一个巨大的启发。

什么启发?先卖个关子,咱们后面再说。先来简单介绍一下这部片子。

《徒手攀岩》记录的是一位叫做Alex的职业攀岩运动员,徒手爬上一座悬崖的过程。那座悬崖,叫做酋长岩,在美国的优山美地国家公园。这块岩石,是地球表面上最大的一块单体花岗岩。高914米,比世界上最高的建筑,迪拜的哈利法塔还要高。纪录片里有一个镜头,Alex在上面爬的时候,就像蚂蚁一样渺小。我在节目文稿里放了一张照片,你可以感受一下,有多么地惊险。

徒手攀岩

请注意,这是徒手攀岩啊。没有任何工具和保护措施,在近乎笔直的悬崖上,要往上攀登将近一公里,全程要几个小时。攀岩者全身的重量,只靠手指和脚尖支撑。而支撑手脚的,可能只是山崖上一块不到2厘米宽的突起。当前进的时候,也就是要换手换脚的时候,全身的支撑点会减少到两个。只要一次失误,只能是粉身碎骨,不会有第二种可能性。

即使是在专业的攀岩运动员看来,这也是一个不可能完成的任务。说白了,就等于送死。但是在纪录片中,Alex说了一句话,非常地奇怪,他说:“风险和后果是两回事。徒手攀岩的风险很低,只是后果很严重。”

哎,这话什么意思?

只要抽身出来一想,就明白了。我们每天出门上班,如果出车祸死了。这个后果确实是很严重。但是这件事风险很高吗?不高啊。只要你小心走路,驾车,遵守交通规则,风险是可控的啊。

你再想,对于一个从来没有进过城的人来说,突然置身在大城市的车水马龙中,他是不是也会觉得很恐慌,觉得这个地方简直就是地狱,分分钟要被车撞死。但是如果你从小生活在城市,逐渐掌握了过马路的行为规则,那你就明白Alex那句话的意思了:风险很低,只是后果很严重。

所以,徒手攀岩这个事,问题仅仅在于,它的风险是不是可控的?

Alex的答案是:可以。只要勤于练习。

你知道他为了这次攀爬,准备了多长时间吗?不是几天,不是几个月,而是八年。在这八年的时间里,Alex在不同的条件下练习攀岩。光酋长岩,他就带着绳子爬过将近60次,一遍一遍地考察路线。每次攀岩回来,第一件事就是记笔记。岩石上,哪个地方有一个微小的凸起可以借力,哪个地方手和脚应该怎么配合,Alex都熟记在胸、倒背如流。

Alex的攀岩路线

所以,最终徒手攀岩的那一天,就像一场大型舞蹈表演。每一个动作都是事先彩排过无数遍的,Alex只需要准确执行,没有什么惊喜。

徒手攀岩这件事,因为在视觉上和想象上都非常刺激,而且后果很严重,所以我们才会觉得不可思议。但是你想,很多专业的顶级高手,不都有这样的神乎其神的技能吗?只不过后果没那么严重而已。

比如,最顶尖的网球运动员,能做到隔空击中对面场地上的一枚硬币。指哪打哪,十发十中。能精确到这种程度。中国菜的厨师,做一道菜叫“文思豆腐”,一块豆腐,横切88刀,竖切188刀,切得跟纸一样薄,还不能碎不能断。不多举例子了,你随便在综艺节目里看一个才艺秀,哪一样不都是让观众惊掉下巴吗?对,很多在我们外行看来不可思议的事情,在内行眼里是可以通过练习抵达的境界。

那除了我们刚才说的动作练习,Alex的功夫还下在哪儿了呢?

他说,最大的风险,不是外界的风吹草动,而是内心的情绪和压力。最大的敌人不是眼前那块陡峭的岩壁,最大的敌人就是自己。

这么听起来有点鸡汤。你想啊,徒手攀岩和一般的攀岩有什么区别?无非就是有绳和没绳嘛。有绳的时候,你会感到安全,可以轻松上阵。没绳的时候,你的每一步行动都事关生死,那个压力是惊人的。压力会把我们击倒,让我们陷在深深的恐惧里,彻底丧失行动的能力。

那怎么办呢?Alex的答案很简单,只能是增加对自己情绪的控制感。

这部纪录片介绍说,Alex每天不是住在房子里,而是住在一辆拖车里,吃饭睡觉都在车里,就是为了靠近悬崖峭壁,好进行训练。他在攀岩以外,主要的时间,就是在拖车里练习引体向上。不是用手掌,而是用手指吊起全身的重量,一吊就是一个小时。这么做,除了训练自己的身体之外,还是对自己情绪的训练,要建立百分之百的控制感。控制到什么程度?控制到能够抑制自己杏仁核的程度。

拖车里练习引体向上

杏仁核,我们都知道,是人的情绪中枢。人之所以会感到恐惧,就是杏仁核活跃的结果。在纪录片里,医生对Alex的大脑做过一次核磁共振,发现他的杏仁核比普通人要平静。换句话说,Alex在攀岩的时候,不会像普通人那样感到恐惧。这是为什么呢?你可以说是基因的原因,Alex的大脑就是异于常人。但Alex自己的解释是,他跟悬崖峭壁相处的时间太长了,所以,他的杏仁核已经习惯了,不会那么容易恐惧了。这是练习的结果。

纪录片中有一个细节,在Alex成功攀登上酋长峰以后,有人问他:“你下午怎么安排?”正常人的回答,要么是说开个Party,庆祝一下,要么是赶紧回家,休息一下。但是Alex的回答是:“我要回拖车,继续引体向上。”你看,八年辛苦训练,一朝成功,一般人肯定是狂喜啊,但是Alex居然都没有一点情绪上的波动。连行为方式上的波动都没有,他还是要回去引体向上。他把自己的情绪已经控制到这种程度。

下面就要说到,我看这部纪录片受到的启发了。

我的启发,其实不仅是训练的重要性。而是一个人成为高手,到底意味着什么?

过去,我们总是觉得,高手,就是获得了自由。别人做不到的,他们做到了。所以他们可以享受更多的随心所欲。

但是,看着Alex攀岩的过程,我突然意识到:不对。高手不是享受更多的自由。恰恰是反过来的,高手是看到了更多的限制。

Alex长期的训练,不只是做到动作熟练而已。他实际上是在感知一个个的限制。这条路线只能这么设计、这块石头只能用这个姿势踩、这个地方的手脚挪动只能按照这个顺序。914米的成功攀登,每一步、每一秒,都是被各种维度的限制规定出来的。这里面哪有什么自由?哪有什么随心所欲?

我举个生活中的例子你就明白了。

比如,我家里要买一个新窗帘,如果不是专业的家居设计师,我只能说,我喜欢哪个颜色的窗帘,能接受的价格区间是什么。但是如果换成专业的家居设计师呢?他会意识到各种维度的限制。比如颜色、材质、式样、材质式样和墙面的配合、不同光照条件下的效果、好不好拆卸、好不好洗涤、耐不耐脏。

你看,专业和业余的区别,不是他更自由,而是他更受限制。所以我一个普通人进到窗帘市场,觉得到处都是选择,而一个专业的家居设计师面对上万个窗帘,可能会觉得,几乎没得选。

前不久,作家周晓枫对我讲了一番话,也暗合了这个道理。

她说,很多人都以为作家的本事是自由创作、文无定法、驰骋想象。其实不然,作家真正的本事是,对一个意思的表达,能做到非常准确。

对,是准确。一个高手之所以是高手,不是因为他在享受更多的自由,而是他看到了更多的限制。成为高手的过程,不是一个更放纵自己的过程,而是一个不断受到约束的过程啊。

好,这个话题就聊到这里。罗辑思维,明天见。

划重点:
一个高手之所以是高手,不是因为他享受更多的自由,而是他看到了更多的限制。 成为高手的过程,不是一个更放纵自己的过程,而是一个不断受到约束的过程。


原文链接

如何实现一个最简单的Vue-Router

如何实现一个最简单的Vue-Router

要自己实现一个mini版的Vue-Router,当然要先了解他(Vue-Router)的原理。以及他都做了些什么?

Vue-Router的实现原理

先来看看Vue-Router官网对自己的介绍:

Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。

那么本文中的mini版Vue-Router会简单实现一些Vue-Router的基础功能:

  • 像真正的Vue-Router一样编写路由(仅基础实现)
  • 实现Vue-Router的hash模式url
  • 声明两个全局组件:router-link,router-view
  • 响应式切换路由视图

1. 提前扫盲,每次我们要引入Vue-Router都要使用以下代码来安装,

1
2
3
4
import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

官方文档的解释:

安装 Vue.js 插件。如果插件是一个对象,必须提供 install 方法。如果插件是一个函数,它会被作为 install 方法。install 方法调用时,会将 Vue 作为参数传入。

Vue.use()会执行传入对象的install方法,以此安装插件

所以,想要我们的Vue-Router能够像官方的写法一致,除了提供类似的构造函数,还需要提供install方法。

2. 编写VueRouter类,以及他的构造函数

新建一个my-vue-router.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
let Vue; // 通过插件传递进来的Vue对象

//创建VueRouter类
export default class VueRouter{

//构造函数
constructor(options) {
this.$options = options;
// 声明map, 把path和component映射
this.routeMap = {};

// current保存当前hash
// vue使其是响应式的
this.app = new Vue({
data: {
current: "/",
},
});
}
}

3. 编写VueRouter的install静态方法

使用Vue.mixin()将router对象绑定到Vue的原型链上

关于混入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//提供install方法
VueRouter.install = function(_Vue) {
Vue = _Vue;

// 混入:挂载$router
Vue.mixin({
beforeCreate() {
// 希望接下来代码在每个组件创建时都执行
// this指当前组件实例
if (this.$options.router) {
Vue.prototype.$router = this.$options.router;
// 初始化router
this.$options.router.init();
}
},
});
};

4. 梳理VueRouter类的结构与逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
export default class VueRouter {

constructor(options) {
//...构造函数
}

init(){
//执行VueRouter的install方法后在这里初始化router

// 1.事件监听
this.bindEvents();
// 2.创建路由映射
this.createRouteMap();
// 3.声明两个全局组件
this.initComponent();
}

}

5. bindEvents方法

监听hashchange事件,每当跟在#符号后面的URL部分(包括#符号)改变,就会触发该事件。
关于hashchange

1
2
3
4
5
6
7
8
bindEvents(){
window.addEventListener("hashchange", this.onHashChange.bind(this));
window.addEventListener("load", this.onHashChange.bind(this));
}
onHashChange(){
//处理一下url,并改变current的值
this.app.current = window.location.hash.slice(1) || "/";
}

6. createRouteMap方法

解析option中的router

1
2
3
4
5
6
// 解析routes选项
createRouteMap() {
this.$options.routes.forEach(item => {
this.routeMap[item.path] = item.component;
});
}

7. initComponent方法(声明组件)

使用Vue.component()方法声明全局组件
使用render()函数渲染router-link组件的dom

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 声明两个组件
initComponent() {
// Vue.component()
Vue.component("router-link", {
props: { to: { type: String, required: true } },
// template: '<a to="/">xxx</a>'
render(h) {
// 1. render生成虚拟dom
// 2. 描述渲染dom结构
// 3. h(tag, data, children)
// return <a href={this.to}>{this.$slots.default}</a>
const vdom = h('a', {attrs: {href: '#'+this.to}}, [this.$slots.default]);
console.log(vdom);
return vdom;
},
});

Vue.component('router-view', {
render: h => {
// this指向VueRouter实例
const component = this.routeMap[this.app.current];
return h(component);
}
})
}

8. 像真正的Vue-Router一样使用!

在router.js中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import Vue from 'vue'
// import Router from 'vue-router'
// 注释掉真正的Vue-Router,使用我们的mini版本QvQ
import Router from './my-vue-router'
import Home from './views/Home.vue'
import About from './views/About.vue'

Vue.use(Router)

export default new Router({
routes: [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/about',
name: 'about',
component: About
},
// {
// path: '/about',
// name: 'about',
// // route level code-splitting
// // this generates a separate chunk (about.[hash].js) for this route
// // which is lazy-loaded when the route is visited.
// component: () => import(/* webpackChunkName: "about" */ './views/About.vue')
// },
]
})

App.vue中

1
2
3
4
5
6
7
8
9
10
11
12
13
<template>
<div id="app">
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<router-view/>
</div>
</template>

<style>
···
</style>

在main.js中引入

1
2
3
4
5
6
7
8
import Vue from 'vue'
import App from './App.vue'
import router from './router'

new Vue({
router,
render: h => h(App)
}).$mount('#app')

OK! 现在你应该可以在项目中看到效果了

小结

因为这是一个mini版本,非常简陋,仅仅实现了最基础的几个功能。

关键代码片段github地址

使用github分支管理博客源码

使用gitHub分支管理博客源码

使用hexo搭建博客后,突然也苦恼于该如何保存博客源码,让我能方便的在多个设备搭建环境写博客?

在知乎上看到了一个相关的问题 ,里面正好有解答。

我也稍稍总结一下,方便自己以后再看的时候,也省得到时候再翻回答。

方法1:

说明:使用gitHub分支来管理博客源码
优点:

  • 简单方便,新建分支后只需要正常提交即可,有另一个分支保存代码,每次切换环境只需要clone下来
    缺点:
  • 其他电脑无法使用hexo d -g命令

方法2:

说明:使用 两个GitHub Repo + 持续集成
优点:

  • 安全,可以把源码放在gitee或coding私有仓库,提交到源码分支后,持续集成会自动执行hexo g命令并且把public文件夹下的代码推送到另一个仓库
    缺点:
  • 我暂时没有分离仓库的需求

方法3:

说明:使用gitHub分支 + 持续集成
优点:

  • 提交到源码分支后,持续集成会自动执行hexo g命令并且把public文件夹下的代码推送到master(githubPage)分支,一目了然。
  • 使用其他电脑也一样可以推送到master分支,且提交记录也会更准确。
    缺点(准确的说是我的缺点):
  • 我不了解持续集成,怎么办?

我选择了方法3:

非常感谢dk大佬,他博客的这篇文章帮助我了解travis CI并引导我完成了自动化集成。

一件事'做得好'比较好,还是'做得快'比较好?

鱼和熊掌不能得兼,你怎么选择:做得好,付出的代价可能是耗时长、成本高;做得快,意味着完成度低、不是精品。

我很赞同一篇文章的结论:做得快更好。

做得快不仅可以让你在单位时间内完成更多的工作,而且 因为你工作得很快,所以你会觉得成本低,从而倾向于做更多。

写一篇博客,你可能需要两天。这是很高的时间成本,你觉得太贵了,于是你很少写。但是,做好一件事的唯一方法,就是多做这件事。 做得越快,这件事的时间成本就越低,你会愿意做得更多。

人们总是倾向于,多消费时间成本低的东西。网站很快,就会多访问;搜索很快,就会多搜索;文章很容易读懂,就会多读几篇。做得快的核心,就是要让时间成本降下来,从而多做。