iframe动态切换src后导致history.back问题

现象

iframe有个奇怪的现象,当我们开发用到iframe嵌套一个网页,动态的改变iframe来实现嵌套网页的切换,这时候会导致history后退变成了iframe后退的问题。这样就会使得点击返回,不是父级页面返回,而是iframe里的页面出现了返回。

解决方法

方案一:对iframe进行销毁

每次动态切换iframe的时候对iframe进行销毁,然后再新建一个iframe。
js直接操作dom,删除对应的iframe,再创建一个新的iframe。
vue使用v-ifreact加判断,angular*ngIf

方案二:js操作dom,在iframe内操作location,用replace来替换src
1
2
const iframe = document.getElementById("iframe");
iframe.contentWindow.location.replace(src);
方案三:使用key

巧用key的特性,在虚拟dom的diff算法中,key有着超高的地位,如果同一类型的虚拟节点的key不相同,就会直接销毁重新挂载,而没有key区分是就会尽可能的复用补丁。

1
2
3
4
5
// vue.js
<iframe :key="src" :src="src" />

// react.js
<iframe key={src} sc={src} />

正则传入变量

有些时候我们匹配的正则需要是动态的,那我们如何在正则中传入变量呢!!
我们使用RegExp来实现。
RegExp 对象

RegExp 对象表示正则表达式,它是对字符串执行模式匹配的强大工具。

创建 RegExp 对象的语法:

new RegExp(pattern, attributes);

参数

参数 pattern 是一个字符串,指定了正则表达式的模式或其他正则表达式。
参数 attributes 是一个可选的字符串,包含属性 “g”、”i” 和 “m”,分别用于指定全局匹配、区分大小写的匹配和多行匹配。ECMAScript 标准化之前,不支持 m 属性。如果 pattern 是正则表达式,而不是字符串,则必须省略该参数。

返回值

一个新的 RegExp 对象,具有指定的模式和标志。如果参数 pattern 是正则表达式而不是字符串,那么 RegExp() 构造函数将用与指定的 RegExp 相同的模式和标志创建一个新的 RegExp 对象。
如果不用 new 运算符,而将 RegExp() 作为函数调用,那么它的行为与用 new 运算符调用时一样,只是当 pattern 是正则表达式时,它只返回 pattern,而不再创建一个新的 RegExp 对象。

抛出

SyntaxError - 如果 pattern 不是合法的正则表达式,或 attributes 含有 “g”、”i” 和 “m” 之外的字符,抛出该异常。
TypeError - 如果 pattern 是 RegExp 对象,但没有省略 attributes 参数,抛出该异常。


简单的来个示例:
1
2
3
4
5
6
7
var str = "我们的好朋友JavaScript";

var target = "JavaScript";

var reg = new RegExp("(" + target + ")", "g"); // /(JavaScript)/g

str.replace(reg, "<strong>$1</strong>");

如何将DOM处理成字符串

??我们如何将DOM变成string呢

方法一:通过innerHTML获取

首先我们创建一个标签,将我们需要获取string的DOM通过appendChild方法加入到标签里,然后就可以使用innerHTML来获取了

1
2
3
4
5
function dom2str(dom) {
var div = document.createElement("div");
div.appendChild(dom);
return div.innerHTML;
}
方法二:通过XMLSerializer获取

XMLSerializerserializeToString()返回DOM子树序列化后的字符串。

1
2
3
4
function dom2str(dom) {
var s = new XMLSerializer();
return s.serializeToString(dom);
}

正则配合replace用法详解

replace用于在字符串中用一些字符替换另一些字符。
语法:
1
stringObject.replace(regexp/substr,replacement)
参数 描述
regexp/substr 必需。规定子字符串或要替换的模式的 RegExp 对象。请注意,如果该值是一个字符串,则将它作为要检索的直接量文本模式,而不是首先被转换为 RegExp 对象。
replacement 必需。替换文本或生成替换文本的函数。

下面看看几种示例:

一、使用$1,$2…的例子
1
2
3
4
5
6
7
8
9
// 正则匹配某个值,并在替换的时候是要匹配的值

// 如将 '我们的好朋友JavaScript',我们要给JavaScript加粗,那就要加一个strong标签

var str = "我们的好朋友JavaScript";

str.replace(/(JavaScript)/, "<strong>$1</strong>");

// $1会匹配到括号里的值 多个的话会按顺序取 $1,$2...
二、第二的参数使用函数
1
2
3
4
5
6
7
8
9
10
11
// 还是如同一的例子

var str = "我们的好朋友JavaScript";

str.replace(/JavaScript/, function(val) {

return "<strong>" + val + "</strong>"

});

// 这里我们可以通过判断来返回需要的替换的值,比较更灵活易懂些
三、模板的应用
1
2
3
4
5
6
7
8
9
10
var data = {

name: "Amy",

age: 20

}
var str = "My name is {{name}}.I am {{age}} years old this year";

str.replace(/{{(.*?)}}/g, function(val, key) {return data[key]});

.*?为非贪婪匹配模式

正则表达式匹配两个字符串之间的值

  • 匹配A与B之间的字符串,包含A与B:

    1
    2
    3
    4
    5
    var a = "A11B22A33B";

    a.match(/A.*?B/g);

    // ["A11B", "A33B"]
  • 匹配A与B之间的字符串,包含A但不包含B:

    1
    2
    3
    4
    5
    var a = "A11B22A33B";

    a.match(/A.*?(?=B)/g);

    // ["A11", "A33"]
  • 匹配A与B之间的字符串,不包含A且不包含B:

    1
    2
    3
    4
    5
    var a = "A11B22A33B";

    a.match(/(?<=A).*?(?=B)/g);

    // ["11", "33"]

浅谈前端程序员学习方法

前端的学习比较杂,但我们可以将前端的学习比作纵向和横向的,纵向的使我们学习到的新的知识,横向的是我们对我们学习到的新知识的拓展。

关于纵向上的学习,我推荐类比的学习方式,例如sasslessvuereactangular,gruntgulpwebpack等。

这里我重点分享一下我横向上拓展的学习方法。

横向上,我觉的就在我们平时的开发项目中发现并学习拓展的。

在我们平时最常做的事情,码代码,我们会遇到各式各样的难题,或是新颖的思路和写法,对于这些的攻克和掌握,就是我们的经验,也就是我们横向的发展,但是拓展也会有深有浅,这里就是我要说的,我们要学会在横向的发展。这里有主动被动,被动就是我们遇到了难题,并解决了难题,主动就是在我们遇到的难题,在解决基础上总结和思考延伸,或者本身就没有遇到难题,我们自己去发现可以延伸学习的东西。

自定义console,更优雅的控制日志输出

作为一个前端的程序员,我们调试的时候经常会用到console来输出日志,对数据进行分析,定位问题,解决问题,然后删掉console日志的代码。以后我们遇到问题出现在同一地方,还是得在同样的地方输出同样的数据进行分析。对于前端有些必要的地方可以保留日志输出的代码,但是这样有个不好的地方就是代码上线了,在控制台还是会有我们调试的日志的输出。

期望:开发的时候控制台能够看到日志,上线的时候看不到日志。

为了能更好的控制,我们会采取一些办法:

  • 第一种,我们可以通过打包工具配置来控制日志的输出

    比如使用webpack,我们可以通过UglifyJS来处理,用webpack 4举个例子:
    首先安装插件:npm i uglifyjs-webpack-plugin --save-dev
    配置选项:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
      	// webpack.config.js
    const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
    module.exports = {
    plugins: [
    new UglifyJsPlugin({
    uglifyOptions: {
    compress: {
    drop_console: true
    }
    }
    })
    ]
    }

    【注】:webpack 内置了 webpack.optimize.UglifyJsPlugin,基于的是 UglifyjsWebpackPlugin v0.4.6 版本

  • 第二种,我们通过改写替换原先的console方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    const environment = 'production';
    // 自定义输出日志
    console.log = (function (logFunc) {
    return function () {
    try {
    if (environment == 'production') {
    // 发布环境,根据实际情况进行定义
    // webapp 可以输出到文件
    } else {
    logFunc.call(console, ...arguments);
    }
    } catch (e) {
    console.error(e);
    }
    }
    })(console.log);

关于项目Git代码管理的一些总结

一、项目Git分支构建

  • master 主分支,只有项目的最高管理的研发具有该分支的操作权限,主分支的代码为线上稳定运行的版本代码;

  • develop 开发分支,研发不允许直接在该分支上进行开发提交代码,该分支的代码为测试环境部署的最新代码;

  • release-(版本号) 该分支是由master分离出的分支,对测试通过的develop上的代码进行merge合并,该分支版本为上线试运行版本,运行没问题后再合并到master分支上;

  • feature-(功能命名分支) 该分支为迭代开发的一个模块功能的需求,有develop分支上切分出来的分支;

  • feature-(功能命名分支)-(功能开发者) 该分支为对应的研发的分支,有功能分支切分出来的代码,该分支仅为本地分支,可以不提交到线上

git账号配置公钥

平时工作的时候会涉及到好几个代码管理的平台,coding gitee github gitlab 或者是自己搭建代码的管理库

这时提交密码设置会很麻烦,有时一个平台甚至有几个账号。

Mac本中git会记住密码,我当时用Mac,各个自己的平台账号用户名和密码都设置的一样,一开始用起来也没什么,后来和别的程序员对接代码库的时候,要提交到他们代码库的时候,https怎么都提交不上去,最后只能用ssh,我删了秘钥的一些东西,配置了秘钥,提交成功了,后来我自己的一些代码库的东西提交不上去了,丢了些东西。经过这么一折腾,还是老老实实的配置个公钥吧。

那我们Mac上如何配置公钥,配置多个公钥呢?

一些方面可以参考 gitee的文档

1
ssh-keygen -t rsa -C "***@***.com" -f ~/.ssh/***_id_rsa

如上命令配置命名一个秘钥,会有三步操作,其中有要输入密码的,不想输入密码,直接回车跳过

由于我们的公钥配置的名字是自定义的,这时我们需要创建一个config文件来指定找到这个文件
将这些内容拷贝进去


# gitee
Host gitee.com
HostName gitee.com
PreferredAuthentications publickey
IdentityFile ~/.ssh/***_id_rsa


1
vi ~/.ssh/config

查看文件的内容,将内容复制粘贴到平台的公钥管理的地方。这样我们就可以提交到对应的平台了。

1
cat ~/.ssh/***_id_rsa.pub

我们可以一个公钥多个平台用,也可以每个平台配置一个,这个看自己需要。

关于使用react-native-http-cache之 cocoapods 管理的ios项目 遇到的坑

关于react-native-http-cache,根据githuba上,第一步我们需要

1
2
3
4
5
yarn add react-native-http-cache

// or

npm install react-native-http-cache --save

然后执行

1
react-native link react-native-http-cache

安卓上我先不说了。但是遇到cocoapods管理的项目,build时会一直报找不到 ***.h,网上也有些方法,改了之后还是会有一堆其他的问题,然后观察别的第三方库发现cocoapods可以管理 react-native-http-cache,于是依样画葫芦,在 Podfile 中加入了 pod 'RCTHttpCache', :path => '../node_modules/react-native-http-cache/ios',但是不如人意,执行 pod install 报找不到 react-native-http-cache 的错误。
仔细观察别的没问题的第三方库时,发现每个库里会有这样一个文件 ***.podspec,于是一样的也在 react-native-http-cache 加入了这样一个文件,命名为 RCTHttpCache.podspec`,我观察看应该文件名是这个依赖的项目名,然后里面还需要填入一些内容,于是继续仿写

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
require "json"

package = JSON.parse(File.read(File.join(__dir__, "../package.json")))
version = package["version"]
giturl = package["repository"]["url"]
bugsurl = package["bugs"]["url"]

Pod::Spec.new do |s|
s.name = "RCTHttpCache"
s.version = version
s.summary = "react-native-http-cache"
s.description = <<-DESC
Control http cache used by fetch/XMLHttpRequest
DESC
s.homepage = giturl
s.license = "MIT"
# s.license = { :type => "MIT" }
s.author = { "tdzl2003" => "git+https://github.com/reactnativecn/react-native-http-cache.git" }
s.platform = :ios, "8.0"
s.source = { :git => giturl, :tag => version }
s.source_files = "RCTHttpCache/*.{h,m}"
s.requires_arc = true


s.dependency "React"
#s.dependency "others"

end

观察看
s.name 及为 依赖中 ios 的项目文件名
s.version 为 版本号
v.summary
s.description 为描述
s.homepage
s.license
s.author 为 作者
s.platform 为 运行系统
s.source
s.source_files 为 加载的代码文件
s.requires_arc
s.dependency 为 依赖的第三方库

这些东西有些不填似乎也没事,我把这个文件拷贝到依赖的ios文件下面,然后执行pod install 成功的导入了 RCTHttpCache

注意这里是手动加入的这个文件,当执行yarn操作别的依赖的时候回删掉该文件,可以做好文档记录,备份一份该文档,或者fork一份代码,加入文件,重新的地址安装该依赖