每次检测到到底,触发函数获取数据
List 组件通过 loading 和 finished 两个变量控制加载状态,当组件滚动到底部时,会触发 load 事件并将 loading 设置成 true。此时可以发起异步操作并更新数据,数据更新完毕后,将 loading 设置成 false 即可。若数据已全部加载完毕,则直接将 finished 设置成 true 即可。
<template>
<div>
<van-list
v-model="loading"
:finished="finished"
finished-text="我是有底线的"
@load="onLoad"
:immediate-check="false">
<van-cell v-for="data in datalist" :key="data.filmId" @click="handleChangePage(data.filmId)">
<img :src="data.poster" />
<div>
<div class="title">{{ data.name }}div>
<div class="content">
<div :class="data.grade ? '' : 'hidden'">观众评分:<span style="color:red;">{{ data.grade }}span>div>
<div class="actors">主演:{{ data.actors | actorsFilter }}div>
<div>
{{ data.nation }}|{{ data.runtime }}分钟
div>
div>
div>
van-cell>
van-list>
div>
template>
<script>
import http from '@/util/http'
import Vue from 'vue'
Vue.filter('actorsFilter', (data) => {
if (data === undefined) return '暂无主演'// 防止有undefined的数据导致无法过滤,造成报错
// 把数据的名字给映射出来
return data.map(item => item.name).join('')
})
export default {
data() {
return {
datalist: [],
loading:false,
finished:false,
current:1
}
},
mounted() {
http({
url: '/gateway?cityId=440100&pageNum=1&pageSize=10&type=1&k=5877842',
headers: {
'X-Host': 'mall.film-ticket.film.list'
}
}).then(res => {
console.log(res.data.data.films)
this.datalist = res.data.data.films
})
},
methods: {
onLoad(){
console.log("到底了")
this.current++
http({
url: `/gateway?cityId=440100&pageNum=${this.current}&pageSize=10&type=1&k=7018656`,
headers: {
'X-Host': 'mall.film-ticket.film.list'
}
}).then(res => {
// console.log(res.data.data.films)
this.datalist = [...this.datalist, ...res.data.data.films]
})
},
handleChangePage(id) {
// console.log(id)
// 编程式导航
//detail/1111
// 1-通过路径跳转
// this.$router.push(`/detail/${id}`)
// 2-通过命名路由跳转
this.$router.push({
name: "vanDetail",
params: {
id
}
})
}
}
}
script>
<style lang="scss" scoped>
.van-list{
.van-cell {
overflow: hidden;
padding: .9375rem;
img {
width: 4.125rem;
height: 5.625rem;
float: left;
}
.title {
font-size: 16px;
}
.content {
font-size: 13px;
color: gray;
.actors {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 12.5rem;
letter-spacing: 2px;
}
}
}
}
style>
解决懒加载数据到底结束
this.total不等于0是解决点击一个电影后返回一上来就触发到底的问题
// 总长度匹配,禁用懒加载功能
if (this.datalist.length === this.total && this.total !==0) {
this.finished = true
return;
}
对于每个页面都起到加载效果,可以封装axios。
http.js
import axios from 'axios'
import { Toast } from 'vant';
const http = axios.create({
baseURL: 'https://m.maizuo.com',
timeout: 1000,
headers: {
'X-Client-Info': '{ "a": "3000", "ch": "1002", "v": "5.2.1", "e": "167643376563166084022273", "bc": "440100" }'
}
})
//在发请求之前拦截--showLoading
http.interceptors.request.use(function (config) {
// Do something before request is sent
// console.log(config)
Toast.loading({
message:'加载中...',
forbidClick:true,
duration:0
})
return config
}, function (error) {
// Do something with request error
return Promise.reject(error);
});
//在成功后拦截--hideLoading
http.interceptors.response.use(function (response) {
// Any status code that lie within the range of 2xx cause this function to trigger
// Do something with response data
// 成功了就清除loading
Toast.clear()
return {
...response,
aaa:'van'
}
}, function (error) {
// Any status codes that falls outside the range of 2xx cause this function to trigger
// Do something with response error
// 失败了也清除loading
Toast.clear()
return Promise.reject(error);
});
export default http
加载:
Toast.loading({
message:'加载中.….',
forbidclick: true
})
是方法 ,需要单独引入
duration展示时长(ms),值为0时,toast不会消失
默认2000
//在成功后拦截--hideloading
http.interceptors.response.use(function (response){
// Any status code that lie within the range of 2xx cause this function to
//trigger
// Do something with response data
vue-axios拦截器 axios还提供了拦截器的功能,他的拦截器是用拦截 请求和响应的,说简单是:请求到服务器前拦截 和 响应到客户端前拦截。
Cinema.vue:
添加
methods:{
handleLeft() {
// console.log('left')
this.$router.push('/city')
}
}
City.vue:
<template>
<div>
<van-index-bar>
<van-index-anchor index="A" />
<van-cell title="A1" />
<van-cell title="A2" />
<van-cell title="A3" />
<van-index-anchor index="B" />
<van-cell title="B1" />
<van-cell title="B2" />
<van-cell title="B3" />
van-index-bar>
div>
template>
<script>
import http from '@/util/http'
export default {
mounted() {
http({
url: '/gateway?k=247794',
headers: {
'X-Host': ' mall.film-ticket.city.list'
}
}).then(res => {
console.log(res.data.data.cities)
})
// 任务:
// 1,316条 ==>A ,B进行分组工
// 2.利用转换后的数组,结合组件库进行渲染页面。
}
}
script>
City.vue:
将城市的数据转换
import http from '@/util/http'
export default {
data() {
return {
cityList: [
]
}
},
mounted() {
http({
url: '/gateway?k=247794',
headers: {
'X-Host': ' mall.film-ticket.city.list'
}
}).then(res => {
// console.log(res.data.data.cities)
this.renderCity(res.data.data.cities)
})
// 任务:
// 1,316条 ==>A ,B进行分组工
// 2.利用转换后的数组,结合组件库进行渲染页面。
},
methods: {
renderCity(list) {
console.log(list)
var cityList = []
var letterList = []
for (var i = 65; i < 91; i++) {
// console.log(String.fromCharCode(i))
letterList.push(String.fromCharCode(i))
}
// console.log( letterList)
letterList.forEach(letter => {
var newList = list.filter(item => item.pinyin.substring(0, 1).toUpperCase() === letter)
// 过滤出包含每个开头的字母
// console.log(newList)
newList.length > 0 && cityList.push({ // 26个字母中有的才进行添加
type: letterList,
list: newList
})
})
// console.log(cityList)
return cityList
}
}
}
</script>
City.vue:
<template>
<div class="city">
<van-index-bar :index-list="computedList" @select="handleChange">
<div v-for="data in cityList" :key="data.type">
<van-index-anchor :index="data.type" />
<van-cell :title="item.name" v-for="item in data.list" :key="item.cityId" @click="handleClick(item)" />
div>
van-index-bar>
div>
template>
<script>
import http from '@/util/http'
import { Toast } from 'vant'
export default {
data() {
return {
cityList: []
}
},
computed: {
// 令右边字母的城市切换选择可以一一对应
computedList() {
return this.cityList.map(item => item.type)
}
}
,
mounted() {
http({
url: '/gateway?k=247794',
headers: {
'X-Host': ' mall.film-ticket.city.list'
}
}).then(res => {
// console.log(res.data.data.cities)
this.cityList = this.renderCity(res.data.data.cities)
})
// 任务:
// 1,316条 ==>A ,B进行分组工
// 2.利用转换后的数组,结合组件库进行渲染页面。
},
methods: {
handleChange(data) {
// console.log("change",data)
Toast(data)
},
renderCity(list) {
console.log(list)
var cityList = []
var letterList = []
for (var i = 65; i < 91; i++) {
// console.log(String.fromCharCode(i))
letterList.push(String.fromCharCode(i))
}
// console.log( letterList)
letterList.forEach((letter) => {
var newList = list.filter(
(item) => item.pinyin.substring(0, 1).toUpperCase() === letter)
// 过滤出包含每个开头的字母
// console.log(newList)
newList.length > 0 && cityList.push({
type: letter,
list: newList
})
})
// console.log(cityList)
return cityList
},
handleClick(item) {
// console.log(item.name, item.cityId)
//一、 传统的多页面方案
// 1.location.href = '#/cinemas?cityname='+item.name
// 2.cookie,localStorage
// 单页面方案,
// 1.中间人模式
// 2. bus事件总线 $on, $emit
// vuex 状态管理模式
}
}
}
script>
<style lang="scss" scoped>
.van-toast--html .van-toast--text {
min-width: 30px
}
style>
vuex是一个专门为vue.js设计的集中式状态管理架构。状态?我把它理解为在data中的属性需要共享给其他vue组件使用的部分,就叫做状态。简单的说就是data中需要共用的属性。
引入Vuex(前提是已经用Vue脚手架工具构建好项目)
1、利用npm包管理工具,进行安装 vuex。在控制命令行中输入下边的命令就可以了。
npm install vuex--save
要注意的是这里一定要加上 –save,因为你这个包我们在生产环境中是要使用的。
2、新建一个store文件夹(这个不是必须的),并在文件夹下新建store.js文件,文件中引入我们的vue和vuex。
3、使用我们vuex,引入之后用Vue.use进行引用。
4、在main.js 中引入新建的vuex文件
5、再然后 , 在实例化 Vue对象时加入 store 对象
vuex的工作流程就是:
(1)通过dispatch去提交一个actions,
(2) actions接收到这个事件之后,在actions中可以执行一些异步|同步操作,根据不同的情况去分发给不同的mutations,
(3)actions通过commit去触发mutations,
(4)mutations去更新state数据,state更新之后,就会通知vue进行渲染
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
// state公共状态
state:{
cityId:'310100',
cityName:'上海'
},
// 统一管理,被devtools 记录状态的修改dd
mutations:{
changeCityName(state,cityName) {
// 通过mutations得到最新传回来的cityName
state.cityName = cityName
// console.log(cityName)
}
}
})
main.js:
import Vue from 'vue' // ES6 导入方式
import App from './App.vue' // 导入根组件App
import router from './router'
import store from './store'
Vue.config.productionTip = false
new Vue({
router, //this.$router === router
store, //this.$store === store
render: h => h(App) // vue 支持的新写法
}).$mount('#app')
vuex 管理保存公共状态,(分散在各个组件内的状态,统一管理,)
注意:
vuex 默认是管理在内存, 一刷新页面,公共状态就丢失了。
vuex 持久化-todo
vuex 项目应用
1.非父子的通信
2.后端数据的缓存快照,减少重复数据请求,减轻服务器压力,提高用户体验
面试坑问题:
如何在 mutations 中做异步请求
但是 mutations只能支持同步,无法做异步
Cinemas.vue:
<template>
<div>
<van-nav-bar title="影院" ref="navbar" @click-left="handleLeft">
<template #left>
{{ $store.state.cityName }}<van-icon name="arrow-down" />
template>
<template #right>
<van-icon name="search" size="20" color="black"/>
template>
van-nav-bar>
<div class="box" :style="{
height: height
}">
<ul>
<li v-for="data in $store.state.cinemaList" :key="data.cinemaId">
<div class="left">
<div class="cinema_name">{{ data.name }}div>
<div class="cinema_text">{{ data.address }}div>
div>
<div class="right">
<div style="color: red;">¥{{ data.lowPrice / 100 }}起div>
div>
li>
ul>
div>
div>
template>
<script>
import BetterScroll from 'better-scroll'
export default {
data() {
return {
cinemaList: [],
height: '0px'
}
},
mounted() {
// console.log(this.$refs.navbar.$el.offsetHeight)
// 动态结算高度,视口高度-底部选项卡的高度-顶部导航栏的高度=中心页面滚动的高度
this.height =
document.documentElement.clientHeight
- this.$refs.navbar.$el.offsetHeight
-document.querySelector("footer").offsetHeight + 'px'
// 一进来就分发getCinema action 并传来cityId
if(this.$store.state.cinemaList.length === 0){
this.$store.dispatch('getCinemaData',this.$store.state.cityId).then(res=>{
// console.log("数据完事了")
this.$nextTick(() => {// 保证dom上树,保证BetterScroll回调,实现初始化滚动
new BetterScroll('.box', {
scrollbar: {
fade: true
}
})
})
})
} else {
console.log('缓存')
this.$nextTick(() => {// 保证dom上树,保证BetterScroll回调,实现初始化滚动
new BetterScroll('.box', {
scrollbar: {
fade: true
}
})
})
}
// http({
// url: `/gateway?cityId=${this.$store.state.cityId}&ticketFlag=1&k=9458654`,
// headers: {
// 'X-Host': 'mall.film-ticket.cinema.list'
// }
// }).then(res => {
// // console.log(res.data)
// this.cinemaList = res.data.data.cinemas
// this.$nextTick(() => {// 保证dom上树,保证BetterScroll回调,实现初始化滚动
// new BetterScroll('.box', {
// scrollbar: {
// fade: true
// }
// })
// })
// })
},
methods:{
handleLeft() {
// console.log('left')
this.$router.push('/city')
}
}
}
script>
<style lang="scss" scoped>
li {
padding: .9375rem;
display: flex;
justify-content: space-between;
.left {
width: 13.25rem;
}
.right {
font-size: 15px;
}
.cinema_name {
font-size: 15px;
}
.cinema_text {
color: #797d82;
font-size: 12px;
margin-top: 5px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.box {
// height: 38.625rem;// 但是rem一直比的是宽度的百分比,所以高度在不同窗口下是会有问题的
overflow: hidden;
position: relative;
// 修正滚动条的的位置
}
style>
store文件 index.js:
import Vue from 'vue'
import Vuex from 'vuex'
import http from '@/util/http'
Vue.use(Vuex)
export default new Vuex.Store({
// state公共状态
state: {
cityId: '310100',
cityName: '上海',
cinemaList:[]
},
// 支持异步和同步
// 从cinemas.vue传来cityId,发起ajax请求
actions: {
getCinemaData(store, cityId) {
return http({
url: `/gateway?cityId=${cityId}&ticketFlag=1&k=9458654`,
headers: {
'X-Host': 'mall.film-ticket.cinema.list'
}
}).then(res => {
// console.log(res.data.data.cinemas)
// 把数据存入vue中
store.commit("changeCinemaData", res.data.data.cinemas)
})
}
},
// 统一管理,被devtools 记录状态的修改
// mutations只能支持同步
mutations: {
changeCityName(state, cityName) {
// 通过mutations得到最新传回来的cityName
state.cityName = cityName
// console.log(cityName)
},
changeCityId(state, cityId) {
state.cityId = cityId
},
changeCinemaData(state,data) {
state.cinemaList = data
}
}
})
vuex三连招:
store/search/index.js
Search…vue:
<template>
<div>
<van-search v-model="value" show-action placeholder="请输入搜索关键词" @search="onSearch" @cancel="onCancel" />
<ul v-if="value">
<li v-for="data in computedList" :key="data.cinemaId">
<div class="left">
<div class="cinema_name">{{ data.name }}div>
<div class="cinema_text">{{ data.address }}div>
div>
<div class="right">
<div style="color: red;">¥{{ data.lowPrice / 100 }}起div>
div>
li>
ul>
div>
template>
<script>
export default {
data() {
return {
value: ''
}
},
computed: {
computedList() {
return this.$store.state.cinemaList.filter(item => item.name.toUpperCase().includes(this.value.toUpperCase()) || item.address.toUpperCase().includes(this.value.toUpperCase()))
}
},
methods: {
onSearch() {
},
onCancel() {
this.$router.back()
}
},
mounted() {
if (this.$store.state.cinemaList.length === 0) {
this.$store.dispatch('getCinemaData', this.$store.state.cityId)
} else {
console.log('缓存')
}
}
}
script>
<style lang="scss" scoped>
li {
padding: .9375rem;
display: flex;
justify-content: space-between;
.left {
width: 13.25rem;
}
.right {
font-size: 15px;
}
.cinema_name {
font-size: 15px;
}
.cinema_text {
color: #797d82;
font-size: 12px;
margin-top: 5px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
style>
(1)应用层级的状态应该集中到单个store 对象中。
(2)提交mutation是更改状态的唯一方法,并且这个过程是同步的
(3)异步逻辑都应该封装到action里面
<template>
<div>
<van-nav-bar title="影院" ref="navbar" @click-left="handleLeft"
@click-right="handleRight">
<template #left>
{{ cityName }}<van-icon name="arrow-down" />
template>
<template #right>
<van-icon name="search" size="28" color="black" />
template>
van-nav-bar>
<div class="box" :style="{
height: height
}">
<ul>
<li v-for="data in $store.state.cinemaList" :key="data.cinemaId">
<div class="left">
<div class="cinema_name">{{ data.name }}div>
<div class="cinema_text">{{ data.address }}div>
div>
<div class="right">
<div style="color: red;">¥{{ data.lowPrice / 100 }}起div>
div>
li>
ul>
div>
div>
template>
<script>
import BetterScroll from 'better-scroll'
import {mapState,mapActions,mapMutations} from 'vuex'
console.log(mapState(['cinemaList']))
export default {
data() {
return {
cinemaList: [],
height: '0px'
}
},
computed:{
a(){
return '111'
},
...mapState(['cinemaList','cityId','cityName'])
},
mounted() {
// console.log(this.$refs.navbar.$el.offsetHeight)
// 动态结算高度,视口高度-底部选项卡的高度-顶部导航栏的高度=中心页面滚动的高度
this.height =
document.documentElement.clientHeight
- this.$refs.navbar.$el.offsetHeight
- document.querySelector("footer").offsetHeight + 'px'
// 一进来就分发getCinema action 并传来cityId
if (this.$store.state.cinemaList.length === 0) {
this.$store.dispatch('getCinemaData', this.$store.state.cityId).then(res => {
// console.log("数据完事了")
this.$nextTick(() => {// 保证dom上树,保证BetterScroll回调,实现初始化滚动
new BetterScroll('.box', {
scrollbar: {
fade: true
}
})
})
})
} else {
console.log('缓存')
this.$nextTick(() => {// 保证dom上树,保证BetterScroll回调,实现初始化滚动
new BetterScroll('.box', {
scrollbar: {
fade: true
}
})
})
}
// http({
// url: `/gateway?cityId=${this.$store.state.cityId}&ticketFlag=1&k=9458654`,
// headers: {
// 'X-Host': 'mall.film-ticket.cinema.list'
// }
// }).then(res => {
// // console.log(res.data)
// this.cinemaList = res.data.data.cinemas
// this.$nextTick(() => {// 保证dom上树,保证BetterScroll回调,实现初始化滚动
// new BetterScroll('.box', {
// scrollbar: {
// fade: true
// }
// })
// })
// })
},
methods: {
...mapActions(['getCinemaData']),
...mapMutations(['']),
handleLeft() {
// console.log('left')
this.$router.push('/city')
// 换城市清空cinemaList
// this.$store.commit('clearCinema')
this.clearCinema()
},
handleRight() {
this.$router.push('/cinemas/Search')
}
}
}
script>
<style lang="scss" scoped>
li {
padding: .9375rem;
display: flex;
justify-content: space-between;
.left {
width: 13.25rem;
}
.right {
font-size: 15px;
}
.cinema_name {
font-size: 15px;
}
.cinema_text {
color: #797d82;
font-size: 12px;
margin-top: 5px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.box {
// height: 38.625rem;// 但是rem一直比的是宽度的百分比,所以高度在不同窗口下是会有问题的
overflow: hidden;
position: relative;
// 修正滚动条的的位置
}
style>
Deatail.vue中导入:
import obj from '@/util/mixinObj'
const obj = {
created(){
this.$store.commit('hide')
// console.log('创建完成')
},
destroyed(){
this.$store.commit('show')
},
methods:{
a(){
console.log("aaaaaaaaaaaaaaaa")
}
}
}
export default obj
<template>
<div class="city">
<van-index-bar :index-list="computedList" @select="handleChange">
<div v-for="data in cityList" :key="data.type">
<van-index-anchor :index="data.type" />
<van-cell :title="item.name" v-for="item in data.list" :key="item.cityId" @click="handleClick(item)" />
div>
van-index-bar>
div>
template>
<script>
import http from '@/util/http'
import { Toast } from 'vant'
import obj from '@/util/mixinObj'
export default {
mixins:[obj],//混入
data() {
return {
cityList: []
}
},
computed: {
// 令右边字母的城市切换选择可以一一对应
computedList() {
return this.cityList.map(item => item.type)
}
}
,
mounted() {
// this.$store.commit('hide')
http({
url: '/gateway?k=247794',
headers: {
'X-Host': ' mall.film-ticket.city.list'
}
}).then(res => {
// console.log(res.data.data.cities)
this.cityList = this.renderCity(res.data.data.cities)
})
// 任务:
// 1,316条 ==>A ,B进行分组工
// 2.利用转换后的数组,结合组件库进行渲染页面。
},
methods: {
handleChange(data) {
// console.log("change",data)
Toast(data)
},
renderCity(list) {
console.log(list)
var cityList = []
var letterList = []
for (var i = 65; i < 91; i++) {
// console.log(String.fromCharCode(i))
letterList.push(String.fromCharCode(i))
}
// console.log( letterList)
letterList.forEach((letter) => {
var newList = list.filter(
(item) => item.pinyin.substring(0, 1).toUpperCase() === letter)
// 过滤出包含每个开头的字母
// console.log(newList)
newList.length > 0 && cityList.push({
type: letter,
list: newList
})
})
// console.log(cityList)
return cityList
},
handleClick(item) {
// console.log(item.name, item.cityId)
//一、 传统的多页面方案
// 1.location.href = '#/cinemas?cityname='+item.name
// 2.cookie,localStorage
// 单页面方案,
// 1.中间人模式
// 2. bus事件总线 $on, $emit
this.$store.commit('changeCityName', item.name) // 改成点击的值
this.$router.back() //回退切换城市
// 但是这样做有隐患——谁都能改这个状态
// 必须经过 mutations 方便管理并且防止恶意修改
// 相当于门禁卡的效果
}
}
}
script>
<style lang="scss" scoped>
.van-toast--html .van-toast--text {
min-width: 30px
}
style>
Vuex为什么要持久化?
原因:因为Vuex是基于内存,存在内存里面的,刷新网页之后就没有了,不会持久化储存
vuex可以实现全局状态管理,即实现所有组件间数据共享,但是刷新页面vuex对象会重新加载,状态(数据)会清空
import Vue from 'vue'
import Vuex from 'vuex'
import http from '@/util/http'
import createPersistedState from 'vuex-persistedstate'
Vue.use(Vuex)
export default new Vuex.Store({
plugins:[createPersistedState(
{
reducer: (state)=>{
return {
cityId:state.cityId,
cityName:state.cityName
}
}
}
)],
// state公共状态
state: {
cityId: '310100',
cityName: '上海',
cinemaList:[],
isTabbarShow:true
},
// 支持异步和同步
// 从cinemas.vue传来cityId,发起ajax请求
actions: {
getCinemaData(store, cityId) {
return http({
url: `/gateway?cityId=${cityId}&ticketFlag=1&k=9458654`,
headers: {
'X-Host': 'mall.film-ticket.cinema.list'
}
}).then(res => {
// console.log(res.data.data.cinemas)
// 把数据存入vue中
store.commit("changeCinemaData", res.data.data.cinemas)
})
}
},
// 统一管理,被devtools 记录状态的修改
// mutations只能支持同步
mutations: {
changeCityName(state, cityName) {
// 通过mutations得到最新传回来的cityName
state.cityName = cityName
// console.log(cityName)
},
changeCityId(state, cityId) {
state.cityId = cityId
},
changeCinemaData(state,data) {
state.cinemaList = data
},
clearCinema(state){
// 不要在外面进行清空的操作——会监听不到清空的行为
state.cinemaList = []
},
show(satte){
state.isTabbarShow = true
},
hide(state){
state.isTabbarShow = false
}
}
})
打开git的官网: https://git-scm.com/
Git创建一个自己的本地仓库 如果我们要把一个项目加入到Git的版本管理中,可以在项目所在的目录用 git init 命令建立一个空的本地仓库,然后再用 git add 命令把它们都加入到Git本地仓库的暂存区(stage or index)中,最后再用 git commit 命令提交到本地仓库里。
利用Git连接远程仓库步骤及常见问题
1.先创建一个文件夹,名字为远程仓库的名称
2.在该文件目录下打开Git Bash
3.输入git init,进行初始化(初次连接时)
4.连接远程仓库(初次连接是下一次进入该文件夹就不用了)
在你想要协同的工作文件夹中打开Git Bash Here,创建一个SSH
key,这里用到了非对称公钥加密体系,生成的公钥放到github的网站上,二生成的私钥放在自己的电脑上,每当需要将文件上传到github上时,服务器就会用事先的公钥与你给出的私钥进行验证,验证是否是真正的用户在操作(原理类似于数字签名)。
多人协作原理
典型的做法是,首先创建一个git服务器,被多个人所操作。
几乎每一种版本控制系统都以某种形式支持分支,一个分支代表一条独立的开发线。
使用分支意味着你可以从开发主线上分离开来,然后在不影响主线的同时继续工作。
Git 分支实际上是指向更改快照的指针。
有人把 Git 的分支模型称为必杀技特性,而正是因为它,将 Git 从版本控制系统家族里区分出来。