迎接学习FE一周年

好久不见,本篇博客内容将延续上一篇博客内容《初试VUX》,我将总结在完成此项目中学习到的一些有趣的事情。

阅读记录:
6月份,我阅读了《图解HTTP》
7月份,我阅读了《JavaScript语言精粹》
8月份,我正在阅读《CSS SECRETS》——很高兴的是,至今年8月底,我学习FE一年了
9月份,我已经准备好迎接《ECMAScript 6 入门》以及《深入理解ES6》啦,已经阅读电子版的《ECMAScript 6 入门》,对ES6有些简单的认识,并慢慢实践中

7月初,分析公司业务需求后,我选择使用VUX完成项目,项目也很顺利的在7月底上线了。

那么以下内容都是通过我查阅我的Commits日志产出。

首先介绍下,本项目中使用到的技术栈:

axios

axios不需要过多介绍了吧,Vue更新至2.0版本后,作者就宣告不再对vue-resource更新,而是推荐的axios。

URLSearchParams API 解决CORS预检请求

问题出在,非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为”预检”请求(preflight)。

那么URLSearchParams API就是axios官方提供的解决方案。使用方法传送门>>

以及浏览器发起XHR的两种请求:简单请求和非简单请求。可以参阅《阮老师 - 跨域资源共享 CORS 详解》

实现文件上传

1
<input class="file" name="file" type="file" accept="image/*" @change="upload"/>
1
2
3
4
5
6
7
8
9
10
11
12
13
upload (event) {
let file = event.target.files[0]
let param = new FormData() // 创建form对象
param.append('upLoad', file, file.name) // 通过append向form对象添加数据
let config = {headers: {'Content-Type': 'multipart/form-data'}} // 添加请求头
axios.post(url, param, config)
.then(function (response) {
// ...
})
.catch(function (error) {
// ...
})
}

vue-router

导航钩子

因为业务逻辑需要,在载入某个路由后执行某些事。

1
2
3
4
5
const router = new VueRouter({ ... })

router.beforeEach((to, from, next) => {
// ...
})

Vue

props

props 可以是数组或对象,用于接收来自父组件的数据。props 可以是简单的数组,或者使用对象作为替代,对象允许配置高级选项,如类型检测、自定义校验和设置默认值。

项目开发过程中,我将数据存在父组件中,由于某些业务场景,需要在子组件A中修改父组件数据,从而更新至子组件B中,最后统一移除props,使用vuex管理数据。

Vuex

每一个 Vuex 应用的核心就是 store(仓库)。”store” 基本上就是一个容器,它包含着你的应用中大部分的状态(state)。Vuex 和单纯的全局对象有以下两点不同:

  1. Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。

  2. 你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交(commit) mutations。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。

Vuex 应用的核心完全契合项目开发。

组件化开发

什么是组件?

组件 (Component) 是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能。在有些情况下,组件也可以是原生 HTML 元素的形式,以 is 特性扩展。

我认为使用组件是有必要的,其必要性在于:

  1. 代码复用
  2. 代码解耦

HTML5范围样式 scoped

CSS属性 fill

for …of

for …of 循环有以下几个特征:

  • 这是最简洁、最直接的遍历数组元素的语法。
  • 这个方法避开了 for …in 循环的所有缺陷。
  • 与 forEach 不同的是,它可以正确响应 break、continue 和 return 语句。
  • 其不仅可以遍历数组,还可以遍历类数组对象和其他可迭代对象。

那 for …of 到底可以干什么呢?

  • 跟 forEach 相比,可以正确响应 break, continue, return。
  • for …of 循环不仅支持数组,还支持大多数类数组对象,例如 DOM nodelist 对象。
  • for …of 循环也支持字符串遍历,它将字符串视为一系列 Unicode 字符来进行遍历。
  • for …of 也支持 Map 和 Set (两者均为 ES6 中新增的类型)对象遍历。

参考: 《知乎 - 深入了解 JavaScript 中的 for 循环》

过场动画

参考vux源码:

以下为提取内容:

main.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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import Vuex from 'vuex'

Vue.use(Vuex)

let store = new Vuex.Store({})

store.registerModule('vux', {
state: {
demoScrollTop: 0,
isLoading: false,
direction: 'forward',
},
mutations: {
updateDemoPosition (state, payload) {
state.demoScrollTop = payload.top
},
updateLoadingStatus (state, payload) {
state.isLoading = payload.isLoading
},
updateDirection (state, payload) {
state.direction = payload.direction
}
},
actions: {
updateDemoPosition ({commit}, top) {
commit({type: 'updateDemoPosition', top: top})
}
}
})

// simple history management
const history = window.sessionStorage
history.clear()
let historyCount = history.getItem('count') * 1 || 0
history.setItem('/', 0)

router.beforeEach(function (to, from, next) {
store.commit('updateLoadingStatus', {isLoading: true})

const toIndex = history.getItem(to.path)
const fromIndex = history.getItem(from.path)

if (toIndex) {
if (!fromIndex || parseInt(toIndex, 10) > parseInt(fromIndex, 10) || (toIndex === '0' && fromIndex === '0')) {
store.commit('updateDirection', {direction: 'forward'})
} else {
store.commit('updateDirection', {direction: 'reverse'})
}
} else {
++historyCount
history.setItem('count', historyCount)
to.path !== '/' && history.setItem(to.path, historyCount)
store.commit('updateDirection', {direction: 'forward'})
}

if (/\/http/.test(to.path)) {
let url = to.path.split('http')[1]
window.location.href = `http${url}`
} else {
next()
}
})

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

App.vue

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
49
50
51
52
53
54
55
<template>
<div id="app">
<transition :name="'vux-pop-' + (direction === 'forward' ? 'in' : 'out')">
<!-- @direction 判断动画样式为in或者out -->
<router-view class="app"></router-view>
</transition>
</div>
</template>

<script>
import { mapState } from 'vuex' // 用引入vuex的mapState

export default {
name: 'app',
computed: { // vuex管理页面
...mapState({
direction: state => state.vux.direction
})
}
}
</script>

<style lang='less'>
.vux-pop-out-enter-active,
.vux-pop-out-leave-active,
.vux-pop-in-enter-active,
.vux-pop-in-leave-active {
will-change: transform;
transition: all 250ms;
height: 100%;
top: 0;
position: absolute;
backface-visibility: hidden;
perspective: 1000;
}
.vux-pop-out-enter {
opacity: 0;
transform: translate3d(-100%, 0, 0);
}
.vux-pop-out-leave-active {
opacity: 0;
transform: translate3d(100%, 0, 0);
}
.vux-pop-in-enter {
opacity: 0;
transform: translate3d(100%, 0, 0);
}
.vux-pop-in-leave-active {
opacity: 0;
transform: translate3d(-100%, 0, 0);
}
.weui-btn:after {
border: none !important;
}
</style>

Webpack 轻度调整

vue-cli已经集成Webpack,执行npm run build后,想实现直接运行index.html即可运行页面。修改以下参数即可实现:

build/utils.js

1
2
3
ExtractTextPlugin.extract({
publicPath: '/gallery/gallery//gallery/gallery/' // 解决CSS样式导出路径问题
})

config/index.js

1
2
3
build: {
assetsPublicPath: '/gallery/' // 解决JS、CSS路径问题
}

修改后src = "",或者url (...)使用相对路径即可。

vue-infinite-scroll - 下拉加载

ESLint

这里要提到ESLint是因为,他可以帮助开发者减少开发中一些不必要的错误(除了逻辑),并且在合作开发时,起到大大的作用,所以请拥抱ESLint。


好了,先这样吧,我要抓紧学习去了~

# Vue, Vux, axios

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×