You are my JavaScript Queen


  • 首页

  • 标签

  • 归档

git仓库迁移的方法

发表于 2018-04-15

近日由于有项目迁移的需求, 所以研究了一下如何迁移Git。
要求是迁移的时候,保证所有的分支和提交记录都在,以便于查找和回档。

  1. 直接新建项目,把原有的代码拷贝进去。
    这种方法没有任何提交记录保留,不行。

  2. 把git文件夹复制过去,其他的项目代码保持不变。
    这种方法很不“计算机”,而且一些冲突文件全覆盖会发现仓库记录将损坏,亲自测试过,所以该方法也不行。

其实本质上只要是把git所有的记录原封不动的放到新项目里,再把原项目的远程仓库地址变动一下就可以达成了。

步骤如下:

1. 克隆原仓库的git镜像

1
git clone --mirror https://github.com/yourname/oldProject.git

这里克隆的全是git的内容,并没有其他代码的东西。

2. 在新的服务上创建新项目 newProject

3. 打开旧项目镜像的目录

1
cd oldProject.git

4. 设置需要迁移的目标路径

1
git remote set-url --push origin http://github.com/yourname/newProject.git

5. 推送到新项目

1
git push --mirror

此时,新项目那里已经有了所有的提交记录和代码。但是我们正在维护的代码,之后的提交也必须提交到新仓库地址上。
还需要做的事是把本地项目代码所在工程的远程仓库地址迁移到新的仓库地址。

1
git remote set-url origin newURL

使用这个命令即可完成地址切换。

想查看远程仓库地址的话使用git remote -v命令。

forEach和map的区别

发表于 2018-02-01

js里关于数组有许多内置方法, forEach()和map()是对数组每个元素进行处理的常用方式, 前阵子加了一个前端技术群, 群主的入群问题就是forEach和map的区别。于是研究了一波。

forEach

特点:

  • 1.可以改变数组本身(并不完全,下文会说),且没有返回值;
  • 2.不能常规操作跳出循环;
  • 3.无法进行链式操作;
  • 4.每一次执行匿名函数的时候,还给其传递了三个参数值:数组中的当前项item,当前项的索引index,原始数组input

刚才说到forEach可以改变数组本身,但不完全,是因为只有元素是引用类型的情况下才可以改变,可以看下面的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var personArr = [
{name:'王工',age:26},
{name:'张工',age:27},
{name:'李工',age:30}
];
personArr.forEach(item => {
item.age = item.age + 1}
);
console.log(personArr) //[{name:'王工',age:27},{name:'张工',age:28},{name:'李工',age:31}]
var salaryArr = [10000, 15000, 20000];
salaryArr.forEach(item => {
item = item + 2000
})
console.log(salaryArr) //[10000, 15000, 20000]

上述代码表示,工作一年后,三位工程师的年龄都长了一岁, 但salaryArr并没有改变,也就是很遗憾,每个人涨薪2000的程序没有按照原有的预想进行变化:)原因就是forEach并不能改变值类型元素的数组。

map

特点:

  • 1.会新建一个数组,需要承载对象,也就意味着原始数组调用它后不会发生变化
  • 2.每一个元素都调用一个回调函数后返回结果
  • 3.不管是forEach还是map,都支持2个参数:回调函数(item,index,list)和上下文。第二个参数的意思是把匿名回调函数中的this进行修改。

map的回调函数里必须有return,可以看一下下列代码

1
2
let newArr = [1,2,3,4,5].map(item => { if(item > 3) return item })
// => [undefined, undefined, undefined, 4, 5]

vue切换页面时保证滚动条在最顶部

发表于 2017-12-22

最近的项目里,首页放了很多跳转的元素,点击以后跳转到相应的页面。
一个最典型的例子,点击下方的“关于我们”,会跳到介绍页面,但因为vue的spa单页面特性导致切换页面只是更换了对应的组件,滚动条的位置是不会发生改变的。
因此需要每次切换一个页面的时候,都让滚动条回到最顶部。
可以在app.vue文件下添加监听,监听$route的变化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// App.vue
export default {
name: 'App',
components: {
MHeader,
MFooter
},
watch:{
'$route':function(to,from){
  document.body.scrollTop = 0
document.documentElement.scrollTop = 0
}
}
}

本文没有技术含量,纯粹是工作过程中的一次优化体验的记录:)

手写代码实现bind功能

发表于 2017-12-20

bind()方法主要就是将函数绑定到某个对象,bind()会创建一个函数,函数体内的this对象的值会被绑定到传入bind()中的第一个参数的值,例如:f.bind(obj),实际上可以理解为obj.f(),这时f函数体内的this自然指向的是obj

举例说明:

1
2
3
4
5
6
7
8
9
10
11
var a = {
b: function() {
var func = function() {
console.log(this.c);
}
func();
},
c: 'hello'
}
a.b(); // undefined 这里的this指向的是全局作用域
console.log(a.c); // hello

1
2
3
4
5
6
7
8
9
10
11
12
var a = {
b: function() {
var _this = this; // 通过赋值的方式将this赋值给that
var func = function() {
console.log(_this.c);
}
func();
},
c: 'hello'
}
a.b(); // hello
console.log(a.c); // hello

手写bind

bind有两个特点:

  • 1.本身返回一个新的函数,所以要考虑new的情况
  • 2.可以“保留”参数,内部实现了参数的拼接
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
Function.prototype.bind2 = function(context){
//传入的必须是函数
if(typeof this != 'function'){
throw new TypeError('Error')
}
const that = this
//保留参数, 以便于之后拼接参数
const args = [...arguments].slice(1);
return function F(){
//如果是被new创建的实例, 那么上下文不会改变
if(this instanceof F){
return new that(...argus, ...arguments)
}
// args.concat(...arguments): 拼接之前和现在的参数
// 注意:arguments是个类Array的Object, 用解构运算符..., 直接拿值拼接
return that.apply(context, args.concat(...arguments))
}
}
//test
function test(arg1, arg2) {
console.log(arg1, arg2)
console.log(this.a, this.b)
}
const test2 = test.bind2({
a: 'a',
b: 'b'
}, 1) // 参数 1
test2(2) // 参数 2
//输出
//1 2
//a b

一道关于Promise面试题的分析

发表于 2017-10-28

Promise已经成为前端界必须掌握的技能了,哪怕不了解promise的内部机制,也一定用过相关的api。那么一个promise和setTimeout结合的面试题就非常时候学习promise的内部机制了。

首先,先看题目:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const first = () => (new Promise((resovle,reject)=>{
console.log(3);
let p = new Promise((resovle, reject)=>{
console.log(7);
setTimeout(()=>{
console.log(5);
resovle(6);
},0)
resovle(1);
});
resovle(2);
p.then((arg)=>{
console.log(arg);
});
}));
first().then((arg)=>{
console.log(arg);
});
console.log(4);

promise对象只有三种状态: pending,fulfilled和rejected。状态会变化且只会变化一次,有两种可能:从pending变成fulfilled;从pending变成rejeced。

上述题目,调用处仅有一次,即:

1
2
3
first().then((arg)=>{
console.log(arg);
});

在任务流里,首先开启了一个first的new Promise操作,输出了3。然后遇到了p,开启另一个new Promise操作,输出了7,遇到定时器,定时器要放入下一轮的任务队列里。
接着往下走,是p的then(简称p.then),加入队列任务,该任务是在定时器之前的。之后是first的then任务(简称f.then)。
延迟的任务队列排好以后,执行最后一行,输出4。
目前,顺序流执行下来,输出是3,7,4。
再执行排列的任务,p.then和f.then,输出1,2.
最后执行定时器,输出5。由于promise对象的状态只会变化一次,所以定时器里的resolve(6)是不会执行的。

最终的输出结果是3,7,4,1,2,5。

element-ui组件库使用心得

发表于 2017-08-11

前言

最近公司要做的项目基本都是后台管理,且业务越来越复杂和多变,我在这个过程中不再自己手写组件,一来开发效率低,二来容易有各种各样的问题,于是我采用了Element-UI来进行开发,在这个过程中,用到了很多组件库,记录一下心得和需要注意的地方。

注意事项

  • 1.开发过程中一定要弄清楚版本号,不同版本对应的组件库数量不同,例如最新版的1.3.5有穿梭框组件,而上一版的1.2.9则没有,同时不同版本里组件的写法也是会略有不同。1.3.5版本的对话框demo在1.2.9版本里没有任何效果。

  • 2.认真严格按照官方demo进行设置,不能只把精力放在template上,关于data的初始化设置也是必须的。如在Select组件,如果不设置data,则得不到正常的选择框效果。

  • 3.form表单组件非常灵活,默认的必填选项,组件会自动在label前加上红色星号表明这是必填项,但是一旦是开发者自己定义的校验规则,则不带有红星号,为了样式统一,我一般全部采取自定义校验规则。

  • 4.我在使用iView的时候遇到了一个场景,点击按钮,弹出弹窗,需要在弹窗里填写相应的字段进行提交,iView并没有去适配这个场景。但是在Element里,可以在弹窗(MessageBox)组件里进行填写和验证,但是也只适用于一般的邮箱电话的填写。如果是较为复杂的表单项,还是应该采取对话框(Dialog)的方式进行。

  • 5.页码组件(Pagination)的总页数不是按照totalPage的方式来,而是按照总条数进行的,因为表格显示每一页的条数并不是固定的,所以使用总条数来计算总页数是更加准确的做法。

  • 6.文件上传组件非常灵活,可以附带其他参数上传,整个上传过程有清晰的执行周期,根据每一个步骤的钩子函数可以定义相关的回调函数。在项目里遇到了一个场景,要同时上传两个name不同的文件和其他相关的文本字段,组件库只能做到一个name里传多个文件,但无法同时传两个不同name的文件。一个上传组件只能对应一个name。我采取的做法是先上传其他文本字段,服务器返回一个标志,然后将这个标志连同文件一起上传,第一个name的文件上传完毕后使用”on-success”钩子函数检测,成功后再上传第二个name的文件。整个过程若较慢,则用loading标志提醒用户等待。

  • 7.对于多选框checkbox或者单选框radio,绑定的v-model一定要设置初始值,否则就无法显示勾选和反选的样式。

  • 8.级联选择器很方便,但是都是在一个select里进行选择,如果场景要求多个单选select实现联动效果,则还是要使用单选select选择器,灵活处理选择器里内置的对象的数据结构。

  • 9.默认的单项选择器Select都是会有一个“请选择”的空项,只有用户选择的时候才会有值。但是对于复杂的表单,我想省去这一个验证项,即初始化进入时该Select就有值,这个值是option里的第一项。那么就需要在data里设置。如果option是从后台获取的,整理好数据结构以后也一定要进行v-model的初始化设置。

  • 10.日期选择器绑定的数据,并不是“所见即所得”。即你在日期选择器的输入框里看到了“2017-05-03”的字样时,它对应绑定的model并不是一个string类型的“2017-05-03”,而是一个date对象。这样如果后台接收date字段要求是string类型就无法正常进行。我的解决方法是使用日期选择器组件的“change”事件,因为用户一定要去选择日期,必然会触发这个事件,这个时候内置的event就是文本框里的string字段了,将这个event的值绑定到对应的data上即可。

如果以后发现了新的坑,我会继续补充

1234
Snapline

Snapline

毕业于香港城市大学
苏州码农
热爱摇滚乐

24 日志
9 标签
GitHub 我的邮箱
Links
  • 张鑫旭
  • 阮一峰
  • 廖雪峰
  • witness
  • 慕课网
  • 掘金前端
  • Vuejs
  • 微信小程序
© 2021 Snapline
特别鸣谢 Hexo
|
主题 — NexT.Pisces v5.1.4