Decorative image frame

前端模块化(1)概述

AMD 是 RequireJS 在推广过程中对模块定义的规范化产出。
AMD 规范内容:https://github.com/amdjs/amdjs-api/blob/master/AMD.md
CMD 是 SeaJS 在推广过程中对模块定义的规范化产出。
CMD 规范内容:https://github.com/seajs/seajs/issues/242

CommonJS 是以在浏览器环境之外构建 JavaScript 生态系统为目标而产生的项目,比如在服务器和桌面环境中。
CommonJS 规范内容:http://wiki.commonjs.org/wiki/CommonJS
中文:http://shouce.jb51.net/webpack/commonjs.html

RequireJS 的标准语法是:

1
2
3
4
5
6
7
8
9
require.config({
paths:{
"jquery":'../lib/jquery.min'
}
});
require(['jquery'],function($){
...
//通过此方式引入jquery才能使用$,接下来正常写jquery代码就好
})

SeaJS 规范的标准语法是:

1
2
3
4
5
6
7
define(function (require, exports, module) {
var $ = require("jquery");

exports.sayHello = function () {
$("#hello").toggle("slow");
};
});
1
2
3
4
5
6
7
8
9
seajs.config({
alias: {
jquery: "http://modules.seajs.org/jquery/1.7.2/jquery.js",
},
});

seajs.use(["./hello", "jquery"], function (hello, $) {
$("#beautiful-sea").click(hello.sayHello);
});

CommonJS 标准语法

1
2
3
module.exports = function (value) {
return value * 2;
};
1
var multiplyBy2 = require("./moduleA");

推荐文章:
https://www.cnblogs.com/fps2tao/p/10823468.html
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Modules

Ubuntu 切换阿里云源

备份 cp /etc/apt/sources.list /etc/apt/sources.backup.list

打开 vim /etc/apt/sources.list

vim 输入 :%d 回车,删除原有内容

复制下面内容

1
2
3
4
5
6
7
8
9
10
11
#阿里源
deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse

更换好源之后执行下方命令更新:
sudo apt-get update
sudo apt-get upgrade

跨域问题探讨 (5)后台处理

这是最难的一块
不多说,代码设置对了就能跨域 1.常规跨域
配置过滤器:即可跨域

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
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter; ;

/**
* 配置跨域
*/
@Configuration
public class CorsConfig {
private Logger logger = LoggerFactory.getLogger(getClass());
private CorsConfiguration buildConfig() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
//corsConfiguration.setAllowCredentials(true);
corsConfiguration.addAllowedOrigin("*"); // 1允许任何域名使用
corsConfiguration.addAllowedHeader("*"); // 2允许任何头
corsConfiguration.addAllowedMethod("*"); // 3允许任何方法(post、get等)
return corsConfiguration;
}

@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", buildConfig()); // 4
logger.info("进入自定义CORS {}", source);
return new CorsFilter(source);
}
}

2.要处理 oauth2 的跨域 需要继续设置
applicontion.yaml 设置

1
2
3
spring:
main:
allow-bean-definition-overriding: true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Order(-1)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
//这里必须处理所有预请求不到为什么哈哈哈
http.requestMatchers().antMatchers(HttpMethod.OPTIONS, "/**")
.and()
.cors()
.and()
.csrf().disable();
}
}

跨域问题探讨(4)Axios与Fetch跨域

JSONP 跨域其实就是利用了 src 标签的特性
看见这代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
axios({
method: "post",
headers: {
Authorization: "Basic QXBpQm9vdDpBcGlCb290U2VjcmV0",
},
url: `http://localhost:9000/oauth/token?grant_type=password&username=${_values.username}&password=${_values.password}`,
})
.then((data) => {
console.log(data);
message.success("登录成功,正在为您跳转...", 1);
// @ts-ignore
this.props.history.push("/");
})
.catch((error) => {
message.error("用户密码错误,或者账户不存在", 3);
});

跨域了,但是没做处理,很简单,因为我在 springboot 里面配置了。
fetch 也同理,就不写了。

跨域问题探讨(3)JSONP

很简单,就是利用

并提供一个回调函数来接收数据(函数名可约定,或通过地址参数传递)。
第三方产生的响应为 json 数据的包装(故称之为 jsonp,即 json padding),形如:
callback({"name":"hax","gender":"Male"})
这样浏览器会调用 callback 函数,并传递解析后 json 对象作为参数。本站脚本可在 callback 函数里处理所传入的数据。
补充:“历史遗迹”的意思就是,如果在今天重新设计的话,也许就不会允许这样简单的跨域了嘿,比如可能像 XHR 一样按照 CORS 规范要求服务器发送特定的 http 头。

注意一下:带 src 都能跨域,只是因为 script 标签方便调用 js 而 img 的话还需要将数据解码。

扩展:jq jsonp 实现: https://github.com/jquery/jquery/blob/master/src/ajax/jsonp.js
axios 与之类似。

跨域问题探讨(2)CORS与预请求

跨域资源共享(CORS) 是一种机制,它使用额外的 HTTP 头来告诉浏览器 让运行在一个 origin (domain) 上的 Web 应用被准许访问来自不同源服务器上的指定的资源。当一个资源从与该资源本身所在的服务器不同的协议端口请求一个资源时,资源会发起一个跨域 HTTP 请求。
比如,站点 http://domain-a.com 的某 HTML 页面通过 的 src 请求 http://domain-b.com/image.jpg。网络上的许多页面都会加载来自不同域的 CSS 样式表,图像和脚本等资源。
出于安全原因,浏览器限制从脚本内发起的跨源 HTTP 请求。 例如,XMLHttpRequest 和 Fetch API 遵循同源策略。 这意味着使用这些 API 的 Web 应用程序只能从加载应用程序的同一个域请求 HTTP 资源,除非响应报文包含了正确 CORS 响应头。
(译者注:这段描述不准确,并不一定是浏览器限制了发起跨站请求,也可能是跨站请求可以正常发起,但是返回结果被浏览器拦截了。)

跨域资源共享( CORS )机制允许 Web 应用服务器进行跨域访问控制,从而使跨域数据传输得以安全进行。现代浏览器支持在 API 容器中(例如 XMLHttpRequestFetch )使用 CORS,以降低跨域 HTTP 请求所带来的风险。

1.其中简单请求不会触发预检机制
**
2.只有复杂的就是带自定义请求头的请求才会触发预检机制。
**
3.如果预检返回状态不是 200 ok 那么就会触发跨域保护

跨域问题探讨(1)预请求

首先我们要知道一点: 出于安全考虑,并不是所有域名访问后端服务都可以。其实在正式跨域之前,浏览器会根据需要发起一次预检(也就是 option 请求),用来让服务端返回允许的方法(如 get、post),被跨域访问的 Origin(来源或者域),还有是否需要 Credentials(认证信息)等。那么浏览器在什么情况下能预检呢?
浏览器将 CORS 请求分为两类:简单请求(simple request)和非简单请求(not-simple-request),简单请求浏览器不会预检,而非简单请求会预检。这两种方式怎么区分?

同时满足下列三大条件,就属于简单请求,否则属于非简单请求

1.请求方式只能是:GET、POST、HEAD
2.HTTP 请求头限制这几种字段:Accept、Accept-Language、Content-Language、Content-Type、Last-Event-ID
3.Content-type 只能取:application/x-www-form-urlencoded、multipart/form-data、text/plain
对于简单请求,浏览器直接请求,会在请求头信息中,增加一个 origin 字段,来说明本次请求来自哪个源(协议+域名+端口)。服务器根据这个值,来决定是否同意该请求,服务器返回的响应会多几个头信息字段

下面看一下预请求

这个是之后的请求

如图所示:上面的头信息中,三个与 CORS 请求相关,都是以 Access-Control-开头。
1.Access-Control-Allow-Origin:该字段是必须的,_ 表示接受任意域名的请求,还可以指定域名
2.Access-Control-Allow-Credentials:该字段可选,是个布尔值,表示是否可以携带 cookie,(注意:如果 Access-Control-Allow-Origin 字段设置_,此字段设为 true 无效)
3.Access-Control-Allow-Headers:该字段可选,里面可以获取 Cache-Control、Content-Type、Expires 等,如果想要拿到其他字段,就可以在这个字段中指定。比如图中指定的 GUAZISSO
非简单请求是对那种对服务器有特殊要求的请求,比如请求方式是 PUT 或者 DELETE,或者 Content-Type 字段类型是 application/json。都会在正式通信之前,增加一次 HTTP 请求,称之为预检。浏览器会先询问服务器,当前网页所在域名是否在服务器的许可名单之中,服务器允许之后,浏览器会发出正式的 XMLHttpRequest 请求,否则会报错。(备注:之前碰到预检请求后端没有通过,就不会发正式请求,然后找了好久原因,原来后端给忘了设置…)Java 后端实现拦截器,排除 Options

禁止滚动(遮罩层)

如何在弹层弹出时阻止底部滑动 最佳方案
网上对这个问题的解答众说纷纭,总结来看原理就下面这几种:
1.阻止 body 滚动的默认行为:
在弹层弹出后给 body 添加 onscroll 事件(移动端阻止 ontouchmove),并通过 preventDefault 让 body 不能滚动,这样的优点是代码量少,能达到一定的效果。但同时缺点也是显而易见的,这样的做法在弹层内容不需要滚动的情况下可以使用,但是在弹层内容也需要滚动的情况下就不行了。
2.body 设置 overflow:hidden:
这种方法通过在弹层弹出后给 body 设置样式 height:100%;overflow:hidden,让 body 无法滚动,亲测 pc 端可以,移动端不起作用(猜测是移动端浏览器的问题),具体原因还请大神来解答。如果不需要考虑移动端,可以使用这种方法,代码也很简洁。
3.body 设置 position:fixed :

在弹层弹出后给 body 设置 position:fixed, pc 端移动端都可以,但是会强制滚动到页面顶部(因为此时 body 已经不能滚动了。scrollTop 被重置为 0),这种方法是最接近完美的解决方法,所以完美的解决办法就是这种方法的增强版。
完美的解决方案:
在将要弹出弹层时候记录当前滚动的位置,将 body 设置为固定定位之后,再将实际显示的区域(不想滚动的区域)最外层进行定位,并将 top 值设置为负的滚动位置值,这样就不会在弹出弹层之后回到页面顶部,然后在弹层关闭后解除 body 的固定定位以及之前不想滚动区域的定位,并滚动到之前记录的位置(设置 scrollTop 的值)。这样就完美解决了弹出弹层后底部会滑动的问题,并且弹层内容可滑动。

示例: 假如已经滚动了 500px 那么此时的代码则是

1
2
3
4
5
6
7
8
<body style="position:fixed">
    <section style="position:fixed;top:-500px">
        <!-- 不想滚动的区域 -->
    </section>
    <section>       
         <!-- 弹层区域 -->
     </section> 
 </body>

具体的逻辑代码,如何操作 dom 结构就不写了, 大家应该也会,只要理解了这个原理,不论是使用 jq 还是原生,使用 vue 或者 react 等的框架,都可以这样解决弹层滑动问题。