Vue & Vuex 入门级研究与发现

为什么研究Vue

作为一个前端开发,不会Vue简直呵呵。—— 某资深前端开发工程师曰。

前兆

我从入门前端,第一次亲密接触的就是React,直到最近team重组,新的leader在一次晨会中曰:“希望以后我们组的前端能使用Vue来开发。”

而我们组的前端,貌似就剩我自己了,另外一个还想着回归Java

这让我这个React起家的小前端工程师,内心一万头XXX...奔腾而过。

当然Vue是很好的(要不然也不会在这BB了)。但是,脱离舒适区是一个痛苦的事情,脱离使用了很久的框架转战新的工具,搁谁都不可能很欢喜。但是,这是一个过程,需要慢慢适应……

突如其来的挑战

PO小姐姐来找我,问我手上活怎么样,是不是还在写bug。我说写的差不多了,呸,改的差不多了!

呵呵呵,那就给你介绍个新活呗。噼里啪啦一通讲。没懂啊。不要紧,我们上楼找帮手。(楼上新办公室,两层办公区,牛X的不要不要的),于是跟着PO小姐姐上楼吸甲醛。

我们组一直都是用Vue做项目啊,如果用React做,以后维护起来……

那好吧,我可以学习Vue。这就是我,学习动力十足的我。

下周二要Demo哦。MMP,今天周五了,回家学习两天,周二你就要一个Vue和H5结合的Demo,还是音乐视频互动感超强的那种?

呵呵哒。我一言不发。我只是来打酱油的,我是来学习的,我是你们的帮手而已,别把希望寄托在一个等待入门的小朋友身上,否则后果自负(客户搞事情,可别拿我当挡箭牌)。

周末,趁热来一发

Vue被赞的一B。至今没用过是不是太low B了。江湖传言,文档维护的相当流弊,何不前往一探究竟 。

于是开始了我学习新技能的一贯作风,啃文档!

好吧,get start,我的最爱,按部就班,照猫画虎,比葫芦画瓢……

来个Vue的ToDoList 吧。

脱了衣服,说干就干。

效果永远如此low B,css 是我不愿提及的痛!

很简单,输入框内填写内容,敲击回车,add one todo.

每个todo 都可以进行remove 和 update ,update 做的比较简单,依旧是输入框输入内容,然后直接点击要更新的todo 的update 按钮即可。

总数量 total 通过vuex 的getters 获得 todos.length。

思路是不是很清晰?道理是不是很简单?你别急,惊喜和意外在后面。

惊喜?!意外?!

写了这么久不上一点代码,有点耍流氓的赶脚。所以,走一波 code。

package.json

{
    "name": "vue-todolist",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
    },
    "author": "peter",
    "license": "ISC",
    "dependencies": {
        "element-ui": "^2.0.10",//这货并没有用到,也就是研究的时候好奇,装上看看
        "vue": "^2.5.13",
        "vue-router": "^3.0.1",//同上
        "vuex": "^3.0.1"
    },
    "devDependencies": {
        "babel-plugin-transform-runtime": "^6.23.0",
        "babel-preset-es2015": "^6.24.1",
        "parcel-bundler": "^1.4.1",//这个可是最新流行的小鲜肉,近乎“0配置”的打包工具
        "parcel-plugin-vue": "^1.5.0",//这个是与上结合食用的插件
        "vue-template-compiler": "^2.5.13",
        "babel-preset-env": "^1.3.2",
        "babel-preset-stage-2": "^6.22.0"
    }
}
复制代码

.babelrc

{
    "presets": [
        "env",
        "stage-2"
    ]
}

复制代码

项目结构

因为太简单,压根也没有任何组件化的余地,所以,components文件夹形同虚设。

store

import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);//重点来了,这玩意一定要在store创建之前use,要不然会出错哦。

const store = new Vuex.Store({
    state: {
        todos: []
    },
    mutations: {
        add: (state, todo) => {
            state.todos.push(todo);
        },
        remove: (state, id) => {
            let index = state.todos.findIndex(v => v.id === id);
            state.todos.splice(index, 1);
        },
        update: (state, update) => {
            let length = state.todos.length;
            for (let i = 0; i < length; i++) {
                let tmpTodo = state.todos[i];
                if (tmpTodo.id === update.id) {
                    state.todos[i].content = update.content;
                    break;
                }
            }
        },
        clear: state => state.todos = []//一会儿这里有惊喜和意外发生!!!
        // clear: state => state.todos.splice(0, state.todos.length) 这行代码才是正解
    },
    getters: {
        count: state => state.todos.length,
    }
});

const commit = store.commit;
const getters = store.getters;

export { store, commit, getters };
复制代码

整体看下来是不是和 mobx 很像。这哪里是很像,这简直就是一模一样(这样说Vue粉儿们会不会砍死我)。

clear方法,我一开始很不由自主的使用了原始暴力而且一贯有效没问题的 = []。后来事实证明,没有一层不变的写法,只有一直变化套路。

这种原始暴力的方式,在我使用Redux 和mobx的过程中简直就是屡试不爽,怎么突然就哑火了呢。

问题是这样的: 虽然这种方式可以将store下state上的todos清空,但是并没有引起视图的变化。

Why?How?What?

划重点来啦!!!

这是clear之前的截图(有devtool就是爽,啥都一目了然、尽收眼底)

这是clear之后的图

咦,我擦,这是什么情况!!! BUG!!!BUG!!!BUG!!!我惊慌失措了!!!

淡定,遇到bug一定要冷静沉着思考分析……

领悟!!!

当我把模式调到查看组件状态时,借助devtool让我恍然大悟。

MMP,store.state.todos 是一个数组,而数组是一个Object,Object是引用类型数据,我将它传递给App的data.todos,等于是做了一次复制(浅拷贝),data保留的是对store.state.todos的引用。

是不是没明白,简单点吧:

store.state.todos-> (old hash:12345)

data.todos-> (old hash:12345)

store.state.todos = [];//这一操作之后,惊喜和意外发生了

store.state.todos->(new hash:98765)

data.todos->(old hash:12345)

// 这里的hash是我为了说明情况儿 XJB 写的,别当真。

//也就是说,暴力赋值空数组时候,state下的todos已经不是原来的那个todos了,
//这个新的数组在内存中占有一份新的地理位置,
//而原来的那个old todos的引用,依旧被data保持着,停留在内存里,成为了bug的滋生地
//还是一种叫做内存泄漏的exception的源泉

复制代码

App.vue

<template>
  <div class="app">
      <h1>Vue ToDoList</h1>
      
      <input 
       @keyup.enter="add"
       @input="input"
       :value="content"
        placeholder="做点什么吧..."/>
      
      <a class="btn-a" @click="clear">Clear</a>
      <a style="font-size:15pt;">total:{{count}}</a>
      <ul>
          <li v-for="t in todos">
              <span>{{t.content}}</span>
              <button @click="update(t.id)">update</button>
              <button @click="remove(t.id)">remove</button>
          </li>
      </ul>
  </div>
</template>

<script>
import { TodoItem } from "./components";
import { store, commit, getters } from "./store";
import todo from "./public/todo";
export default {
  name: "App",
  data() {
    return {
      todos: store.state.todos,
      content: ""
    };
  },
  computed: {
    count: () => getters.count
  },
  methods: {
    input: function(e) {
      this.content = e.target.value;
    },
    add: function(e) {//ES5写法多了几个字母,但是大大滴不一样哦
      let t = new todo();
      t.content = this.content;
      commit("add", t);
      this.content = "";
    },
    remove: id => {//注意这方法的写法与ES5写法的不同,很飘逸,
      commit("remove", id);
    },
    update: function(id) {
      commit("update", { id, content: this.content });
      this.content = "";
    },
    clear: () => commit("clear")
  }
};
</script>
复制代码

没办法,写到这种地步,只能咬牙继续,是谁说要好好学习的……

Vue 的基本属性 methods 的定义,让我百思不得其解了一小会儿。

比如,上述代码中看到的 add ,input update 这三个方法,我都采用了ES5的写法,通过function关键字定义函数;而remove和clear两个,我则使用了ES6的箭头函数写法。

同样是方法,怎么差距就这么大呢!!!

其实一开始,我清一色的写的箭头函数,但是发现,有问题,问题很简答,this = undefined。

我就纳闷了,这尼玛又是什么鬼,也来不及再去Google了,之前乱投医,试一试吧,换成了ES5,嘿,无药而治,立竿见影,奇迹般地好了!

真相只有一个! —— 柯南。

如同没有无缘无故的爱,也没有无缘无故的恨那般,没有可能我随便一改写法,就奇迹般的好了!

肯定有原因!

箭头函数表达式的语法比函数表达式更短,并且不绑定自己的this,arguments,super或 new.target。这些函数表达式最适合用于非方法函数,并且它们不能用作构造函数。 MDN

有没有很清楚很明白,没有吧。

作为一个在React里漫天飞舞箭头函数绑定this的小前端而言,这么机器的翻译,我才不会当真呢!

廖雪峰

看了廖老师的文章,赶紧换了套路----->

MMP,这就是不问所以然,就XJB写的下场!

仔细想一想吧。

能够调试是一件多么幸福的事情,一目了然的看到,function函数内的this指向的是整个VueComponent,而在箭头函数内,毛都没有!为啥呢?廖雪峰老师说的很明白了,就是说,箭头函数的this指向调用方的,而我将add方法通过@符号绑定给了input标签,而且在函数加载的过程中,input标签还没有挂载完毕呢,所以,箭头函数在那一瞬间,毛也咩有捕获到,所以它的this是个undefined,而function函数就不一样了,它在初始化的时候,捕捉到的是整个对象本身(VueComponent),所以……

虽然不知道这种理解方式对不对,但是暂时这样认为吧,回头再找大神求证。

尾声

罗里吧嗦写了这么多,时间都是23:17了,也该告一段落了,对于我这个Vue新生儿来说,这一天折腾的已经不少了。

希望能够在往后的日子里,和她相爱不相杀。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值