vue2实现商城的源码(vue电商项目源码)
本文目录一览:
- 1、使用vue2+Vuex+Router重写饿了么点餐系统和vue插件简析
- 2、【面试题解析】从 Vue 源码分析 key 的作用
- 3、理解VUE2双向数据绑定原理和实现
- 4、使用vue2+Vuex+Router 重写饿了么点餐系统和 vue 插件简析
使用vue2+Vuex+Router重写饿了么点餐系统和vue插件简析
vue有自己的脚手架构建工具vue-cli,使用起来非常方便,使用webpack来集成各种开发便捷工具,比如:
代码热更新,修改代码之后网页无刷新改变,对前端开发来说非常的方便
PostCss,再也不用去管兼容性的问题了,只针对chrome写css代码,会自动编译生成支持多款浏览器的css代码
Eslint,统一代码风格,规避低级错误,对于有代码洁癖的人来说是绝对的好东西,不过有些地方的代码校验有时候也挺麻烦的-.-
bable,ES2015出来已经有一段时间了,但是不少浏览器还没有兼容ES6.有了bable,放心使用ES6语法,它会自动转义成ES5语法。
Stylus,类似于SASS/SCSS,但是可以不写{}和“:”,使用起来还是很方便的
…
除此之外,vue-cli已经使用node配置了一套本地服务器和安装命令等,本地运行和打包只需要一个命令就可以搞定,非常的方便
开发
vue非常好的融合了react的组件化思想和angular的指令思想。
一个vue的组件将HTML、CSS、JS代码写在一个文件里面,这样既方便编写,也方便管理和修改
Axios
在vue1.x的时候,vue的官方推荐HTTP请求工具是vue-resource,但是在vue2.0的时候将推荐工具改成了axios。
使用方式都差不多,但需要注意的是:接口返回的res并不直接是返回的数据,而是经过axios本身处理过的json对象。真正的数据在res.data里:
axios.get(url).then((res)={
this.data = res.data
})
Vuex
vue提供了一个数据管理工具vuex,有点类似于angular中factory和service,可以进行数据上的通信。
比如存储一些公共变量或者是不同组件间的数据处理等。
这个有一些高级用法在这里不细说,想要了解的可以去官方文档看,有中文版本。
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++
}
}
})
Vue-Router
vue-router是vue的路由系统,可以用来创建单页应用。基本思想是在主页面中引入标签,然后定义路由,把router挂在到app上,然后把各个子页面渲染到view里面。使用起来还是很方便的,
跳转页面只需要
router.push('test')
获取元素节点
vue2.0废除了v-el指令,所有的节点指令修改为ref,然后通过ref来获取元素节点,如
div ref="testHook"test/div
...js code
this.$ref.testHook
组件间的通信
一。如果是和子组件通信,则使用ref就可以实现,如:
test ref="testHook"/test
...js code
this.$ref.testHook.add() //调用test子组件的add方法
二。使用emit来发送广播
vue2提供了一套广播机制,即一边发送广播,一边接收广播来执行相应操作。使用方法如下:
比如想要给test组件发送一个“相加”广播:
export default {
method:{
click(){
Vue.$emit('add',{}) //第二个参数可作为传递数据传送到监听端口,不需要则传空对象
}
}
}
那么test组件中就需要监听,在created方法里写
export default {
created(){
Vue.$on('add',this.add)
},
method:{
add(){
this.count++
}
}
}
除了以上总结的这点小的知识点以外,还有很多vue的知识想要和大家分享,以后会陆续写出来,大家感兴趣的也可以来我的GitHub一起来写这个项目(觉得不错的给个star Hah)
【面试题解析】从 Vue 源码分析 key 的作用
最近看了面试题中有一个这样的题, v-for 为什么要绑定 key?
Vue 中 key 很多人都弄不清楚有什么作用,甚至还有些人认为不绑定 key 就会报错。
其实没绑定 key 的话,Vue 还是可以正常运行的,报警告是因为没通过 Eslint 的检查。
接下来将通过源码一步步分析这个 key 的作用。
Virtual DOM 最主要保留了 DOM 元素的层级关系和一些基本属性,本质上就是一个 JS 对象。相对于真实的 DOM,Virtual DOM 更简单,操作起来速度更快。
如果需要改变 DOM,则会通过新旧 Virtual DOM 对比,找出需要修改的节点进行真实的 DOM 操作,从而减小性能消耗。
传统的 Diff 算法需要遍历一个树的每个节点,与另一棵树的每个节点对比,时间复杂度为 O(n²)。
Vue 采用的 Diff 算法则通过逐级对比,大大降低了复杂性,时间复杂度为 O(n)。
VNode 更新首先会经过 patch 函数, patch 函数源码如下:
vnode 表示更新后的节点,oldVnode 表示更新前的节点,通过对比新旧节点进行操作。
1、vnode 未定义,oldVnode 存在则触发 destroy 的钩子函数
2、oldVnode 未定义,则根据 vnode 创建新的元素
3、oldVnode 不为真实元素并且 oldVnode 与 vnode 为同一节点,则会调用 patchVnode 触发更新
4、oldVnode 为真实元素或者 oldVnode 与 vnode 不是同一节点,另做处理
接下来会进入 patchVnode 函数,源码如下:
1、vnode 的 text 不存在,则会比对 oldVnode 与 vnode 的 children 节点进行更新操作
2、vnode 的 text 存在,则会修改 DOM 节点的 text
接下来在 updateChildren 函数内就可以看到 key 的用处。
key 的作用主要是给 VNode 添加唯一标识,通过这个 key,可以更快找到新旧 VNode 的变化,从而进一步操作。
key 的作用主要表现在以下这段源码中。
updateChildren 过程为:
1、分别用两个指针(startIndex, endIndex)表示 oldCh 和 newCh 的头尾节点
2、对指针所对应的节点做一个两两比较,判断是否属于同一节点
3、如果4种比较都没有匹配,那么判断是否有 key,有 key 就会用 key 去做一个比较;无 key 则会通过遍历的形式进行比较
4、比较的过程中,指针往中间靠,当有一个 startIndex endIndex,则表示有一个已经遍历完了,比较结束
从 VNode 的渲染过程可以得知,Vue 的 Diff 算法先进行的是同级比较,然后再比较子节点。
子节点比较会通过 startIndex、endIndex 两个指针进行两两比较,再通过 key 比对子节点。如果没设置 key,则会通过遍历的方式匹配节点,增加性能消耗。
所以不绑定 key 并不会有问题,绑定 key 之后在性能上有一定的提升。
综上,key 主要是应用在 Diff 算法中,作用是为了更快速定位出相同的新旧节点,尽量减少 DOM 的创建和销毁的操作。
希望以上内容能够对各位小伙伴有所帮助,祝大家面试顺利。
Vue 的文档中对 key 的说明如下:
关于就地修改,关键在于 sameVnode 的实现,源码如下:
可以看出,当 key 未绑定时,主要通过元素的标签等进行判断,在 updateChildren 内会将 oldStartVnode 与 newStartVnode 判断为同一节点。
如果 VNode 中只包含了文本节点,在 patchVnode 中可以直接替换文本节点,而不需要移动节点的位置,确实在不绑定 key 的情况下效率要高一丢丢。
某些情况下不绑定 key 的效率更高,那为什么大部分Eslint的规则还是要求绑定 key 呢?
因为在实际项目中,大多数情况下 v-for 的节点内并不只有文本节点,那么 VNode 的字节点就要进行销毁和创建的操作。
相比替换文本带来的一丢丢提升,这部分会消耗更多的性能,得不偿失。
了解了就地修改,那么我们在一些简单节点上可以选择不绑定 key,从而提高性能。
如果你喜欢我的文章,希望可以关注一下我的公众号【前端develop】
理解VUE2双向数据绑定原理和实现
1.vue 双向数据绑定是通过 数据劫持 结合 发布订阅模式的方式来实现的, 也就是说数据和视图同步,数据发生变化,视图跟着变化,视图变化,数据也随之发生改变;
2.核心:关于VUE双向数据绑定,其核心是 Object.defineProperty()方法;
3.介绍一下Object.defineProperty()方法
(1)Object.defineProperty(obj, prop, descriptor) ,这个语法内有三个参数,分别为 obj (要定义其上属性的对象) prop (要定义或修改的属性) descriptor (具体的改变方法)
(2)简单地说,就是用这个方法来定义一个值。当调用时我们使用了它里面的get方法,当我们给这个属性赋值时,又用到了它里面的set方法;
这样我们就能实现js的双向数据绑定,也对这个方法有初步的了解 ;
这个例子实现的效果是:随着文本框输入文字的变化,span中会同步显示相同的文字内容;这样就实现了 model = view 以及 view = model 的双向绑定。
通过添加事件监听keyup来触发set方法,而set再修改了访问器属性的同时,也修改了dom样式,改变了span标签内的文本。
1.实现效果
先来看一下vue双向数据绑定是如何进行的,以便我们确定好思考方向
2.任务拆分
拆分任务可以让我们的思路更加清晰:
(1)将vue中的data中的内容绑定到输入文本框和文本节点中
(2)当文本框的内容改变时,vue实例中的data也同时发生改变
(3)当data中的内容发生改变时,输入框及文本节点的内容也发生变化
3.开始任务1——绑定内容
我们先了解一下 DocuemntFragment(碎片化文档) 这个概念,你可以把他认为一个dom节点收容器,当你创造了10个节点,当每个节点都插入到文档当中都会引发一次浏览器的回流,也就是说浏览器要回流10次,十分消耗资源。
而使用碎片化文档,也就是说我把10个节点都先放入到一个容器当中,最后我再把容器直接插入到文档就可以了!浏览器只回流了1次。
注意:还有一个很重要的特性是,如果使用appendChid方法将原dom树中的节点添加到DocumentFragment中时,会删除原来的节点。
举个例子:
可以看到,我的app中有两个子节点,一个元素节点,一个文本节点
但是,当我通过DocumentFragment 劫持数据一下后
注意:我的碎片化文档是将子节点都劫持了过来,而我的id为app的div内已经没有内容了。
同时要主要我while的判断条件。判断是否有子节点,因为我每次appendChild都把node中的第一个子节点劫持走了,node中就会少一个,直到没有的时候,child也就变成了undefined,也就终止了循环。
来实现内容绑定
我们要考虑两个问题,一个是如何绑定要input上,另一个是如何绑定要文本节点中。
这样思路就来了,我们已经获取到了div的所以子节点了,就在DocumentFragment里面,然后对每一个节点进行处理,看是不是有跟vm实例中有关联的内容,如果有,修改这个节点的内容。然后重新添加入DocumentFragment中。
首先,我们写一个处理每一个节点的函数,如果有input绑定v-model属性或者有{{ xxx }}的文本节点出现,就进行内容替换,替换为vm实例中的data中的内容
然后,在向碎片化文档中添加节点时,每个节点都处理一下。
创建Vue的实例化函数
效果图如下:
我们成功将内容都绑定到了输入框与文本节点上!
4、实现任务2——【view = model
对于此任务,我们从输入框考虑,输入框的问题,输入框如何改变data。我们通过事件监听器keyup,input等,来获取到最新的value,然后通过Object.defineProperty将获取的最新的value,赋值给实例vm的text,我们把vm实例中的data下的text通过Object.defineProperty设置为访问器属性,这样给vm.text赋值,就触发了set。set函数的作用一个是更新data中的text,另一个等到任务三再说。
首先实现一个响应式监听属性的函数。一旦有赋新值就发生变化
然后,实现一个观察者,对于一个实例 每一个属性值都进行观察。
改写编译函数,注意由于改成了访问器属性,访问的方法也产生变化,同时添加了事件监听器,把实例的text值随时更新
实例函数中,观察data中的所有属性值,注意增添了observe
最终我们改变input中的内容能改变data中的数据,单页面却没有刷新
4、实现任务3——【model = view】
通过修改vm实例的属性 该改变输入框的内容 与 文本节点的内容。
这里涉及到一个问题 需要我们注意,当我们修改输入框,改变了vm实例的属性,这是1对1的。
但是,我们可能在页面中多处用到 data中的属性,这是1对多的。也就是说,改变1个model的值可以改变多个view中的值。
这就需要我们引入一个新的知识点:
订阅/发布者模式
订阅发布模式(又称观察者模式)定义了一种一对多的关系,让多个观察者同时监听某一个主题对象,这个主题对象的状态发生改变时就会通知所有观察者对象。
发布者发出通知 = 主题对象收到通知并推送给订阅者 = 订阅者执行相应操作
1
举个例子:
之前提到的set函数的第二个作用 就是来提醒订阅者 进行noticy操作,告诉他们:“我的text变了!” 文本节点变成了订阅者,接到消息后,立马进行update操作
回顾一下,每当 new 一个 Vue,主要做了两件事:第一个是监听数据:observe(data),第二个是编译 HTML:nodeToFragement(id)。
在监听数据的过程中,我们会为 data 中的每一个属性生成一个主题对象 dep。
在编译 HTML 的过程中,会为每个与数据绑定相关的节点生成一个订阅者 watcher,watcher 会将自己添加到相应属性的 dep 容器中。
我们已经实现:修改输入框内容 = 在事件回调函数中修改属性值 = 触发属性的 set 方法。
接下来我们要实现的是:发出通知 dep.notify() = 触发订阅者的 update 方法 = 更新视图。
这里的关键逻辑是:如何将 watcher 添加到关联属性的 dep 中。
注意: 我把直接赋值的操作改为了 添加一个 Watcher 订阅者
那么,Watcher又该做些什么呢?
首先,将自己赋给了一个全局变量 Dep.target;
其次,执行了 update 方法,进而执行了 get 方法,get 的方法读取了 vm 的访问器属性,从而触发了访问器属性的 get 方法,get 方法中将该 watcher 添加到了对应访问器属性的 dep 中;
再次,获取属性的值,然后更新视图。
最后,将 Dep.target 设为空。因为它是全局变量,也是 watcher 与 dep 关联的唯一桥梁,任何时刻都必须保证 Dep.target 只有一个值。
最终我们就实现了这个双向数据绑定功能,虽然很繁琐,但我相信,你多打几遍,一定会对你有所帮助,加油吧!!
使用vue2+Vuex+Router 重写饿了么点餐系统和 vue 插件简析
vue有自己的脚手架构建工具vue-cli,使用起来非常方便,使用webpack来集成各种开发便捷工具,比如:
代码热更新,修改代码之后网页无刷新改变,对前端开发来说非常的方便
PostCss,再也不用去管兼容性的问题了,只针对chrome写css代码,会自动编译生成支持多款浏览器的css代码
Eslint,统一代码风格,规避低级错误,对于有代码洁癖的人来说是绝对的好东西,不过有些地方的代码校验有时候也挺麻烦的-.-
bable,ES2015出来已经有一段时间了,但是不少浏览器还没有兼容ES6.有了bable,放心使用ES6语法,它会自动转义成ES5语法。
Stylus,类似于SASS/SCSS,但是可以不写{}和“:”,使用起来还是很方便的
…
除此之外,vue-cli已经使用node配置了一套本地服务器和安装命令等,本地运行和打包只需要一个命令就可以搞定,非常的方便
开发
vue非常好的融合了react的组件化思想和angular的指令思想。 一个vue的组件将HTML、CSS、JS代码写在一个文件里面,这样既方便编写,也方便管理和修改
Axios
在vue1.x的时候,vue的官方推荐HTTP请求工具是vue-resource,但是在vue2.0的时候将推荐工具改成了axios。
使用方式都差不多,但需要注意的是:接口返回的res并不直接是返回的数据,而是经过axios本身处理过的json对象。真正的数据在res.data里:
axios.get(url).then((res)={
this.data = res.data
})
Vuex
vue提供了一个数据管理工具vuex,有点类似于angular中factory和service,可以进行数据上的通信。 比如存储一些公共变量或者是不同组件间的数据处理等。
这个有一些高级用法在这里不细说,想要了解的可以去官方文档看,有中文版本。
复制代码
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++
}
}
})
axios.get(url).then((res)={
this.data = res.data
})
复制代码
Vue-Router
vue-router是vue的路由系统,可以用来创建单页应用。基本思想是在主页面中引入标签,然后定义路由,把router挂在到app上,然后把各个子页面渲染到view里面。使用起来还是很方便的, 跳转页面只需要
router.push('test')
获取元素节点
vue2.0废除了v-el指令,所有的节点指令修改为ref,然后通过ref来获取元素节点,如
div ref="testHook"test/div ...js code this.$ref.testHook
组件间的通信
一。如果是和子组件通信,则使用ref就可以实现,如:
test ref="testHook"/test
...js code
this.$ref.testHook.add() //调用test子组件的add方法
二。使用emit来发送广播
vue2提供了一套广播机制,即一边发送广播,一边接收广播来执行相应操作。使用方法如下:
比如想要给test组件发送一个“相加”广播:
复制代码
export default {
method:{
click(){
Vue.$emit('add',{}) //第二个参数可作为传递数据传送到监听端口,不需要则传空对象
}
}
}
复制代码
那么test组件中就需要监听,在created方法里写
复制代码
export default {
created(){
Vue.$on('add',this.add)
},
method:{
add(){
this.count++
}
}
}