一、Git(掌握)
Git是一个免费的开源分布式版本控制系统,它可以快速高效地处理从小型到大型的项目。简单点说就是:git分布式版本控制工具(管理代码版本)。我们常用的Git平台有:Gitee(码云)、GitLab、GitHub等。
1、下载Git
这里提供Git下载地址:https://git-scm.com/downloads
2、Gitee配置SSH公钥
注册(用邮箱注册),并登录到Gitee后,鼠标移至右上角头像,下拉选项中选择 设置
怎么生成本机的公钥?请查看:https://gitee.com/help/articles/4181
3、Git日常操作
克隆代码 (把远程仓库拉取到本地):git clone 仓库地址
查看仓库状态 : git status
提交工作区代码到暂存区 : git add 文件路径或者**.(所有文件)**
**提交暂存区代码到历史记录区:**git commit -m '本次提交的信息提示'
**提交历史记录区的历史提交记录到远程仓库:**git push origin 分支名称
注意点
git提示的信息里面只要有fatal 或者error 这两个词随便一个,都是执行git命令失败了
4、创建项目与分支
在gitee中创建项目(例如创建了 demo0630
这个项目),执行以下命令:
复制 // 克隆仓库到本地
git clone git@ gitee .com:codesohigh / demo0630 .git
// 检查当前分支
git branch
一般此时是master分支,但我们开发阶段一般用dev等其他分支,所以我们:
复制 git checkout - b dev
// git checkout 命令加上 -b 参数,表示创建并切换,以上操作相当于:
git branch dev
git checkout dev
在仓库没有初始化前,如果需要检查分支,一定要记住这句话:
未曾commit的仓库是无法检查分支的!
实际上git checkout 不是切换分支的最佳选择,我们使用git switch 会更好:
复制 git switch - c dev // 创建并切换到新的dev分支
git switch dev // 切换到已有的dev分支
5、文件提交
创建 index.js
文件,随便写点内容,提交:
复制 git add .
git commit - m '修改了index.js'
git push origin dev
此时你会发现,git checkout master
切回master分支后,index.js这份文件会消失,因为当前分支不存在这个文件。
6、分支合并
假设当前项目已经完成,我们想要把dev分支合并到master,可以在master分支下使用:
此时,你会看到,项目中又有 index.js
了。
7、版本回滚
使用 git switch -c dev1
创建新的dev1分支,稍微修改dev1中的index.js,并且提交到远程仓库。
我们提交完成后,发现自己不想用当前代码,想回滚到上一次的代码,怎么办呢?
复制 // 查看当前项目提交过的所有版本(含所有分支的操作)
git log
// git log会出现很详细的信息,如果我们只想简单看看版本号,可以使用
git log -- pretty = oneline
我们会得到:
复制 b2ff1beb92bd3ac425dac2fa519d4b8191438be9 ( HEAD -> dev1) '123456'
c9efd011b471765fc9fdd6eefaadf75b3b36153b (origin / dev1) '12345'
80f6cb77a9b13cd471b725b5ef66901150bf57bb '提交'
47 d676dbf6d0687d76f059ee9ed044c4c378ed30 (origin / master , origin / HEAD ) 'dev1的首次提交'
d5c756afd04abfdbc9bb2299064eab34b30ede5f (origin / dev , dev) '修改了index.js'
65f4c72f6c8e2c272d4e284c103e249c65ebff32 Initial commit
如果我们只想回滚到指定版本,可以使用:
这里只需要写id号的前几个字母与数字就行,没必要全写,git会自动去检索。
但此时,我们再一次查看所有版本,发现:
复制 c9efd011b471765fc9fdd6eefaadf75b3b36153b (origin / dev1) '12345'
80f6cb77a9b13cd471b725b5ef66901150bf57bb '提交'
47 d676dbf6d0687d76f059ee9ed044c4c378ed30 (origin / master , origin / HEAD ) 'dev1的首次提交'
d5c756afd04abfdbc9bb2299064eab34b30ede5f (origin / dev , dev) '修改了index.js'
65f4c72f6c8e2c272d4e284c103e249c65ebff32 Initial commit
最新写的那个丢失了。但我此时又后悔了,怎么办?
复制 // 重新reset即可找回
git reset -- hard b2ff1
现在,就可以退回最新版本了。
但这个方法前提是你当前这个控制台不曾关掉,如果已经关掉了,你是没法知道版本号的,这时候要怎么办呢?
复制 // Git提供了一个命令git reflog用来记录你的每一次命令
git reflog
8、代码冲突
修改master的代码,执行:
复制 git add .
git commit -m '提交master'
然后执行:
我们会发现,vscode提示代码冲突:
此时,我们只需要点击我们想要的选项,即可解决代码冲突。
二、Vuex(掌握)
首先,这里提供一套预习视频,点击此处:《简单快速撸懂vuex 》
1、什么是Vuex?
官方定义:
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
说得直白点,vuex就是vue.js中管理数据状态的一个库,通过创建一个集中的数据存储,供程序中所有组件访问。
vuex有以下常用的几个核心属性概念:
具体用法我们稍后揭晓。
2、实际场景
普通的父传子和子传父,或是兄弟组件之间的互传值,都是两个组件之间的数据连接,但如果数据需要多组件共享,并且数据量庞大,那么就不适宜用中央事件总线来解决。此时,我们需要一个更加强大的,能够维护庞大数据的东西,它就是vuex,我们称之为:状态管理。
3、什么时候用vuex?
是不是学了就必须要在项目中使用呢?来看官网的回答:
很显然,如果你的项目比较简单,建议还是别强行使用vuex了。
另外,值得注意的点:vuex会随着页面刷新或关闭,将所有数据恢复至最初始的状态,所以它并不能替代localStorage。
4、安装vuex
如果你的项目是较为大型的,那么建议在创建项目时直接选择安装vuex,如果创建时并未选择安装,请参考:《官网vuex安装 》。
5、State
vuex中的state类似于data,用于存放数据,只不过这个数据是所有组件公用的。
我们来实现一个计数功能,但咱们把数据存放到vuex中的state,这里是专门用来存放组件共享的数据的。来看一下怎么实现:
首先,在 store/index.js
中:
复制 import Vue from 'vue'
import Vuex from 'vuex'
Vue .use (Vuex)
export default new Vuex .Store ({
state : {
num : 0 // 定义了一个num
}
})
然后在组件中:
复制 <template>
<div>
<h3>{{$store.state.num}}</h3>
</div>
</template>
如此这般,我们获取到了state中的数据:
但在html中写这么长一串,始终有点难以阅读,因此,可以在computed中获取这个值,再传入html中:
复制 computed : {
num (){
return this . $store . state .num
}
}
// 标签中
< h3 >{{num}}</ h3 >
那么能否在data中存储这个数据呢?比如这样:
复制 data () {
return {
num : this . $store . state .num
};
} ,
答案是可以的,但不太建议。因为data中的数据可以修改,但通常唯一能够修改state的方式是通过vuex中的mutations,所以此处我们了解一下即可。
6、Getters
vuex中的getters类似于computed计算属性,getters的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
store/index.js
中:
复制 import Vue from 'vue'
import Vuex from 'vuex'
Vue .use (Vuex)
export default new Vuex .Store ({
state : {
num : 2
} ,
getters : {
// 这里的参数state可以让我们快速获取到仓库中的数据
doubleNum (state) {
return state .num * 2 ;
}
}
})
组件中:
复制 <template>
<div>
<h3>{{num}}</h3>
</div>
</template>
<script>
export default {
computed: {
num(){
return this.$store.getters.doubleNum
}
}
};
</script>
7、Mutations
官网指出:
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。
OK!那我们来修改一下这个num:
store/index.js
中(这里暂时先把getters去掉,避免大家学习混乱):
复制 import Vue from 'vue'
import Vuex from 'vuex'
Vue .use (Vuex)
export default new Vuex .Store ({
state : {
num : 2
} ,
mutations : {
// payload专业名称为“载荷”,其实就是个参数
addNum (state , payload) {
state .num += payload;
}
}
})
组件中:
复制 <template>
<div>
<h3>{{num}}</h3>
<button @click="btnClick">累加2</button>
</div>
</template>
<script>
export default {
computed: {
num(){
return this.$store.state.num
}
},
methods: {
btnClick(){
// 使用commit来触发事件,第二个参数是要传递给payload的数据
this.$store.commit('addNum', 2)
}
}
};
</script>
来看看效果:
有一个必须注意的点,Mutations中不允许出现异步操作,它必须是一个同步函数,来看官网的解释:
我们来亲自尝试一下:
复制 mutations : {
addNum (state , payload) {
// 这里给mutations添加定时器,也相当于是异步操作
setTimeout (() => {
state .num += payload;
} , 1000 )
}
} ,
来看看效果:
8、Actions
Action 类似于 mutation,不同在于:
Action 提交的是 mutation,而不是直接变更状态。
复制 import Vue from 'vue'
import Vuex from 'vuex'
Vue .use (Vuex)
export default new Vuex .Store ({
state : {
num : 2
} ,
mutations : {
addNum (state , payload) {
state .num += payload;
}
} ,
actions : {
// context是一个对象,包含了commit和state
AsyncAddNum (context , payload) {
setTimeout (() => {
context .commit ( 'addNum' , payload)
} , 1000 )
}
}
})
组件中:
复制 <template>
<div>
<h3>{{num}}</h3>
<button @click="btnClick">累加2</button>
</div>
</template>
<script>
export default {
computed: {
num(){
return this.$store.state.num
}
},
methods: {
btnClick(){
// dispatch是分发到意思,其实也是触发Actions中的方法
this.$store.dispatch('AsyncAddNum', 2)
}
}
};
</script>
当然,上面actions中的写法有点累赘,我们还可以改写:
复制 AsyncAddNum ({ commit } , payload) {
setTimeout (() => {
commit ( 'addNum' , payload)
} , 1000 )
}
// 如果你还想获取state中的值,可以这样:
AsyncAddNum ({ commit , state } , payload) {
console .log ( state .num); // 2
setTimeout (() => {
commit ( 'addNum' , payload)
} , 1000 )
}
那么,既然actions中可以拿到state的值,能否直接改这个值,而不触发mutations呢?答案是可以的,但...还是devtool的问题:
可以看到,devtool并未更改值,因此,我们还是需要借助mutations来实现值的修改。
9、辅助函数
获取单个数据或触发某个方法比较容易,我们直接拿到和触发就行,但如果要获取的数据和触发的方法很多个,我们就比较麻烦了,这时候我们需要借用辅助函数。比如,我们刚刚只写了累加,现在再补充一个递减。然后来看看辅助函数怎么用。
复制 import Vue from 'vue'
import Vuex from 'vuex'
Vue .use (Vuex)
export default new Vuex .Store ({
state : {
num : 2 ,
title : '标题'
} ,
getters : {
doubleNum (state) {
return state .num * 1 ;
}
} ,
mutations : {
addNum (state , payload) {
state .num += payload;
} ,
cutNum (state , payload) {
state .num -= payload;
}
} ,
actions : {
AsyncAddNum ({ commit } , payload) {
setTimeout (() => {
commit ( 'addNum' , payload)
} , 300 )
} ,
AsyncCutNum ({ commit } , payload) {
setTimeout (() => {
commit ( 'cutNum' , payload)
} , 300 )
}
}
})
此时,要拿到num和title的话,我们可以在组件中:
复制 <template>
<div>
<h2>{{title}}</h2>
<h3>{{num}}</h3>
</div>
</template>
<script>
// 引入辅助函数mapState
import {mapState} from 'vuex'
export default {
// 在computed中引用
computed: {
...mapState(['title', 'num'])
}
};
</script>
如果打算从getters中取出num:
复制 <h3>{{doubleNum}}</h3>
<script>
import {mapState, mapGetters} from 'vuex'
export default {
computed: {
...mapState(['title']),
...mapGetters(['doubleNum'])
}
};
</script>
如果打算把mutations和actions中的方法引入:
复制 <template>
<div>
<h2>{{title}}</h2>
<h3>{{doubleNum}}</h3>
<button @click="addNum(2)">累加2</button>
<button @click="AsyncCutNum(2)">递减2</button>
</div>
</template>
<script>
import {mapState, mapGetters, mapMutations, mapActions} from 'vuex'
methods: {
// 这里负责引入,我们把引入后的事件直接写在标签上,顺便把参数也带上
...mapMutations(['addNum']),
...mapActions(['AsyncCutNum'])
}
</script>
如果你必须把点击事件写在methods中,而不是标签上的话,你也可以这样:
复制 <template>
<div>
<button @click="btnClick1">累加2</button>
<button @click="btnClick2">递减2</button>
</div>
</template>
<script>
import {mapState, mapGetters, mapMutations, mapActions} from 'vuex'
export default {
methods: {
...mapMutations(['addNum']),
...mapActions(['AsyncCutNum']),
btnClick1(){
// 直接通过this.xxx来调用辅助函数引入的事件
this.addNum(2)
},
btnClick2(){
this.AsyncCutNum(2)
}
}
};
</script>
10、Module
假设我们把累加单独抽出来作为一个模块,在store下新建一个 add/index.js
文件:
复制 export default {
namespaced : true , // 命名空间,为true时,可以在store中把当前模块文件夹名称(add),当作模块名使用
state : {
num : 2
} ,
getters : {
doubleNum (state) {
return state .num * 1 ;
}
} ,
mutations : {
addNum (state , payload) {
state .num += payload;
}
} ,
actions : {
AsyncAddNum ({ commit } , payload) {
setTimeout (() => {
commit ( 'addNum' , payload)
} , 300 )
}
}
}
把有关累加的所有内容,都移动至本文件。再到原来仓库index.js中的modules添加:
复制 import add from './add'
export default new Vuex .Store ({
... ,
modules : {
add
}
})
在组件中使用时,稍微有些变化:
复制 ... mapState ({
'title' : 'title' ,
'num1' : 'num1' ,
'num' : state => state . add .num // module中state值的获取方法和getters等不太一样,需要写函数形式
}) ,
... mapGetters ({
'doubleNum' : 'add/doubleNum'
})
... mapMutations ({
'addNum' : 'add/addNum'
})
11、拆分写法
实际上我们可以把state、getter、mutation、action和module都抽离出来,这样可以让store文件看着更加简洁。我们来将 store/index.js
进行拆分:
state.js
:
复制 export default {
num1 : 0 ,
title : '标题'
}
mutations.js
:
复制 export default {
cutNum (state , payload) {
state .num1 -= payload;
}
}
actions.js
:
复制 export default {
AsyncCutNum ({ commit } , payload) {
setTimeout (() => {
commit ( 'cutNum' , payload)
} , 300 )
}
}
modules.js
:
复制 import add from './add'
export default {
add
}
最后,在 store/index.js
中:
复制 import Vue from 'vue'
import Vuex from 'vuex'
import state from './state'
import mutations from './mutations'
import actions from './actions'
import modules from './modules'
Vue .use (Vuex)
export default new Vuex .Store ({
state ,
mutations ,
actions ,
modules
})
12、MutationTypes与ActionTypes
有时候,我们mutations和actions中,同个事件名要出现在好几份文件,如果一个出错,就很难检查是哪里的问题,所以我们可以把这些事件名归到一个js文件,由它来统一调配:
mutationTypes.js
中:
复制 export const CUT_NUM = 'cutNum'
mutations.js
中:
复制 import { CUT_NUM } from '@/store/mutationTypes'
export default {
[ CUT_NUM ](state , payload) {
state .num1 -= payload;
}
}
actionTypes.js
中:
复制 export const ASYNC_CUT_NUM = 'AsyncCutNum' ;
actions.js
中:
复制 import { ASYNC_CUT_NUM } from '@/store/actionTypes'
export default {
[ ASYNC_CUT_NUM ]({ commit } , payload) {
setTimeout (() => {
commit ( 'cutNum' , payload)
} , 300 )
}
}
组件中:
复制 import { ASYNC_CUT_NUM } from '@/store/actionTypes'
import {mapState , mapGetters , mapMutations , mapActions} from 'vuex'
... mapActions ([ ASYNC_CUT_NUM ]) ,
三、作业
请使用vuex写一个TodoList,并在gitee上建立一个仓库,把项目push上去。
注意:
项目不需要使用LocalStorage。