2021/3/10的一面,内容如下:
1. 你觉得前端开发是什么
答:前端开发是做页面呈现和用户交互的。
2. 你觉得你擅长前端开发哪方面?
答:页面呈现,因为对vue框架比较熟悉,所以对页面的呈现比较擅长。
3. get和post请求的区别?
(1)get在浏览器回退时是无害的,但是post会重新提交请求。
(2)get请求可以被浏览器收藏为书签,而post不行。
(3)get会被浏览器主动缓存,而post不会,除非手动设置。
(4)get只支持url编码,而post支持多种编码(下面有补充)
(5)get的请求参数会被完整的记录在历史记录里,而post中的参数不会被保留
(6)get请求的参数是通过url传递的,而post是在request body中,因此get请求有长度限制并且不够安全,post请求没有长度限制而且比较安全。
(7)对于参数的类型,get只接收ASCII字符,而post没有限制。(一般我们都是用ASCII编码)
(8)GET产生一个TCP数据包(get请求一次性发送header和data);POST产生两个TCP数据包(先发header等服务器返回状态码100 continue后再发送data数据包)。
补充:
post支持的编码类型有:application/x-www-form-urlencoded、multipart/form-data、application/json、text/xmlxhr.open("POST","http://www.example.com",true) xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
(1)application/x-www-form-urlencode:是url编码,提交的数据按照 key1=val1&key2=val2 的方式进行编码。默认是编码类型。
(2)multipart/form-data:当表单需要上传文件时,form的enctype必须设置为这个类型。
(3)application/json:是用来告诉服务端消息主体是序列化后的 JSON 字符串。
(4)text/xml:使用XML 作为编码方式。
4. get和post请求的应用场景?
get主要用于请求数据,而post主要用于修改数据。
(1)如果请求有副作用,例如,数据库内添加新的数据行。
(2)如果表单收集上来的数据过程,则使用post。
(3)如果表单不是用ASCII编码,则要用post请求。
5. 如果有3个promise函数,要按一定的顺序执行,可以用什么方法?
(1)调用then执行,例如:
a().then(b).then(c)
(2)用async/await方法,进行异步调用。例如:async function foo(){ await A(); await B(); await C(); }
6. js的异步加载方式有哪些,有什么区别?
渲染引擎遇到 script 标签会停下来,等到执行完脚本,继续向下渲染,这样会阻止浏览器的后续解析,只有当前加载完成才能进行下一步操作,所以默认同步执行才是安全的。但是这样如果JS中有输出document内容、修改dom、重定向的行为,就会造成页面阻塞。所以一般建议把
<script>
标签放在<body>
结尾处,这样尽可能减少页面阻塞。
异步加载又被称为非阻塞加载,浏览器在下载JS的同时,还会进行后续页面处理。
(1)async属性只适用于外部脚本,不能保证脚本按顺序执行,异步下载一旦下载完立即执行会阻塞页面渲染。是H5的新特性。
(2)defer属性只适用于外部脚本,能保证脚本按顺序执行,异步下载等到DOM树渲染完之后才执行,兼容所有浏览器。
(3)创建一个立即函数,在函数里面动态创建script标签。例如:(function(){ var scriptEle = document.createElement("script"); scriptEle.type = "text/javasctipt"; scriptEle.async = true; scriptEle.src = "http://cdn.bootcss.com/jquery/3.0.0-beta1/jquery.min.js"; var x = document.getElementsByTagName("head")[0]; x.insertBefore(scriptEle, x.firstChild); })();
(4)把插入script的方法放在一个函数里面,然后放在window的onload方法里面执行,这样就解决了阻塞onload事件触发的问题。
<script type="text/javascript"> window.onload = function(){ javascript代码 } </script>
注:DOMContentLoaded与load的区别。前者是在document已经解析完成,页面中的dom元素可用,但是页面中的图片,视频,音频等资源未加载完,作用同jQuery中的ready事件;后者的区别在于页面所有资源全部加载完毕。
(5)es6模块type="module"属性
浏览器对于带有type=”module”的<script>
,都是异步加载,不会造成堵塞浏览器,即等到整个页面渲染完,再执行模块脚本,等同于打开了<script>
标签的defer属性 。<script type="module" src="XXX.js"></script>
7. 组件间的通信?
props
、$emit/$on
、vuex
、$parent/$children
、$attrs/$listeners
、provide/inject
参考:https://www.cnblogs.com/fundebug/p/10884896.html
(1)props:父组件向子组件传递数据,是单向传递。
//App.vue父组件 <template> <div id="app"> <users v-bind:users="users"></users>//前者自定义名称便于子组件调用,后者要传递数据名 </div> </template> <script> import Users from "./components/Users" export default { name: 'App', data(){ return{ users:["Henry","Bucky","Emily"] } }, components:{ "users":Users } }
//users子组件 <template> <div class="hello"> <ul> <li v-for="user in users">{{user}}</li>//遍历传递过来的值,然后呈现到页面 </ul> </div> </template> <script> export default { name: 'HelloWorld', props:{ users:{ //这个就是父组件中子标签自定义名字 type:Array, required:true } } } </script>
(2)
$emit/v-on
:子组件向父组件传递数据。通过事件形式。// 子组件 <template> <header> <h1 @click="changeTitle">{{title}}</h1>//绑定一个点击事件 </header> </template> <script> export default { name: 'app-header', data() { return { title:"Vue.js Demo" } }, methods:{ changeTitle() { this.$emit("titleChanged","子向父组件传值");//自定义事件 传递值“子向父组件传值” } } } </script>
// 父组件 <template> <div id="app"> <app-header v-on:titleChanged="updateTitle" ></app-header>//与子组件titleChanged自定义事件保持一致 // updateTitle($event)接受传递过来的文字 <h2>{{title}}</h2> </div> </template> <script> import Header from "./components/Header" export default { name: 'App', data(){ return{ title:"传递的是一个值" } }, methods:{ updateTitle(e){ //声明这个函数 this.title = e; } }, components:{ "app-header":Header, } } </script>
(3)组件间的数据传输:
var Event=new Vue();Event.$emit(事件名,数据);/Event.$on(事件名,data=>{});
<div id="itany"> <my-a></my-a> <my-b></my-b> <my-c></my-c> </div> <template id="a"> <div> <h3>A组件:{{name}}</h3> <button @click="send">将数据发送给C组件</button> </div> </template> <template id="b"> <div> <h3>B组件:{{age}}</h3> <button @click="send">将数组发送给C组件</button> </div> </template> <template id="c"> <div> <h3>C组件:{{name}},{{age}}</h3> </div> </template> <script> var Event = new Vue();//定义一个空的Vue实例 var A = { template: '#a', data() { return { name: 'tom' } }, methods: { send() { Event.$emit('data-a', this.name); } } } var B = { template: '#b', data() { return { age: 20 } }, methods: { send() { Event.$emit('data-b', this.age); } } } var C = { template: '#c', data() { return { name: '', age: "" } }, mounted() {//在模板编译完成后执行 Event.$on('data-a',name => { this.name = name;//箭头函数内部不会产生新的this,这边如果不用=>,this指代Event }) Event.$on('data-b',age => { this.age = age; }) } } var vm = new Vue({ el: '#itany', components: { 'my-a': A, 'my-b': B, 'my-c': C } }); </script>
(4)vuex:适用于任何场景。实现了一个单向数据流,在全局拥有一个 State 存放数据。
通过this.$store.state.xxx
调用
(5)多级嵌套数据时,实现跨级通信,顶级传到最低级。可用$attrs/$listeners
。
$Attrs
:包含了父作用域中不被 prop 所识别 (且获取) 的特性绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过v-bind="$attrs"
传入内部组件。通常配合interitAttrs
选项一起使用。$listeners
:包含了父作用域中的 (不含.native
修饰器的)v-on
事件监听器。它可以通过v-on="$listeners"
传入内部组件。// index.vue <template> <div> <h2>浪里行舟</h2> <child-com1 :foo="foo" :boo="boo" :coo="coo" :doo="doo" title="前端工匠" > /child-com1> </div> </template> <script> const childCom1 = () => import("./childCom1.vue"); export default { components: { childCom1 }, data() { return { foo: "Javascript", boo: "Html", coo: "CSS", doo: "Vue" }; } }; </script>
// childCom1.vue <template class="border"> <div> <p>foo: {{ foo }}</p> <p>childCom1的$attrs: {{ $attrs }}</p> <child-com2 v-bind="$attrs"></child-com2> </div> </template> <script> const childCom2 = () => import("./childCom2.vue"); export default { components: { childCom2 }, inheritAttrs: false, // 可以关闭自动挂载到组件根元素上的没有在props声明的属性 props: { foo: String // foo作为props属性绑定 }, created() { console.log(this.$attrs); // { "boo": "Html", "coo": "CSS", "doo": "Vue", "title": "前端工匠" } } }; </script>
// childCom2.vue <template> <div class="border"> <p>childCom2: {{ $attrs }}</p> </div> </template> <script> export default { props: { coo: String, title: String } }; </script>
(6)provide/inject
允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。provide / inject API 主要解决了跨级组件间的通信问题,不过它的使用场景,主要是子组件获取上级组件的状态,跨级组件间建立了一种主动提供与依赖注入的关系。(详细请看参考文档)
(7)$parent
/$children
与ref
- ref:用于获取一整个组件实例,用于父子间传输
$parent
/$children
:访问父 / 子实例
详细解释请看参考链接总结
常见使用场景可以分为三类:
- 父子通信:
父向子传递数据是通过props
,
子向父是通过events($emit)
;
通过父链 / 子链也可以通信($parent
/$children
);
ref
也可以访问组件实例;
provide
/inject API
;
$attrs
/$listeners
- 兄弟通信:
Bus
;Vuex
- 跨级通信:
Bus
;Vuex
;provide
/inject API
、$attrs
/$listeners
8、用过哪些响应式布局?
响应式布局是指一个网站可以兼容多个终端。
参考:https://www.cnblogs.com/dreamsboy/p/5656009.html
一、 设置meta标签(设置在head里面,可以同时出现多个meta标签)
(参考:https://blog.csdn.net/zhangank/article/details/94014629
- meta 元素被用于规定页面的描述、关键词、文档的作者、最后修改时间以及其他元数据。
- 可用于浏览器(如何显示内容或重新加载页面),搜索引擎(关键词),或其他 web 服务。
- meta里的数据是供机器解读的,告诉机器该如何解析这个页面,也可以添加服务器发送到浏览器的http头部内容
- 它的属性有:content(必需的,因为这是对name和http-equiv的解释或者说是赋值)、http-equiv、name、scheme(h5删除)、chartset(h5添加)
1、name属性
用用于描述网页。
它的值:
(1) Keywords(关键字):为搜索引擎提供关键字列表
语法:<meta name="keywords" content="程序员,程序猿,攻城狮"/>
(2) Description(简介):告诉搜索引擎该网站的主要内容
语法:<meta name="description" content="meta标签是HTML中的一个重要标签,它位于HTML文档头部的<HEAD>标签和<TITL>标签之间。"/>
(3) robots(机器人向导):用于告诉搜索机器人哪些也页面需要索引,哪些页面不需要索引。
语法:<meta name="robots" content=""/>
(content:all,none,index,noindex,follow,nofollow,默认值是all)
参数说明:
- all :文件将被检索,且页面上的链接可以被查询;
- none :文件将不被检索,且页面上的链接不可以被查询;
- index :文件将被检索;
- follow :页面上的链接可以被查询;
- noindex :文件将不被检索,但页面上的链接可以被查询;
- nofollow :文件将被检索,但页面上的链接不可以被查询;
(4)author(作者):标注网页作者
语法:<meta name="author" content="TG,TG@qq.com"/>
(5)copyright(版权):标注版权
语法:<meta name="copyright" content="本网站版权归TG所有"/>
(6)generator(编辑器):说明网站采用什么编译器制作
语法:<meta name="generator" content="你所用的编辑器"/>
(7)revisit-after(重访):网站重访
语法:<meta name="revisit-after" content="7days"/>
HTML5 新增:
(8)viewport(视图):能优化移动浏览器的显示(屏幕的缩放)
语法:<meta name="viewport" content="width=device-width, initial-scale=1.0,maximum-scale=1.0, user-scalable=no"/>
参数值:
- width:viewport的宽度[device-width | pixel_value],pixel-value大部分安卓不支持,但ios支持。
- height:viewport的高度(范围223-10,000)
- user-scalable:yes | no 是否允许缩放
- initial-scale: num 初始化比例(0-10)
- minimum-scale:num 允许缩放的最小比例
- maximum-scale:num 允许缩放的最大比例
(9)format-detection(忽略电话号码和邮箱):忽略电话号码和邮箱
语法:
<meta name="format-detection" content="telephone=no">
(忽略页面中的数字识别为电话号码)<meta name="format-detection" content="email=no"/>
(忽略页面中的邮箱格式识别为邮箱)<meta name="format-detection" content="telphone=no, email=no"/>
(10)renderer(渲染内核):控制浏览器选择何种内核进行渲染。
语法:
- 若页面需默认用极速核,增加标签:
<meta name="renderer" content="webkit">
- 若页面需默认用ie兼容内核,增加标签:
<meta name="renderer" content="ie-comp">
- 若页面需默认用ie标准内核,增加标签:
<meta name="renderer" content="ie-stand">
(11)apple-mobile-web-app-capable(webapp全屏模式)
语法:<meta name="apple-mobile-web-app-capable" content="yes" />
(12)apple-mobile-web-app=status-bar-style(隐藏状态栏、设置状态栏颜色):只有开启WebApp全屏模式时才生效。
content: default | black | black-translucent
语法:<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
不同浏览器:(详细请看参考链接)2、http-equiv属性
用于添加服务器发送到浏览器的http头部内容。
参数说明:
(1)Expires(期限):指定网页在缓存的过期时间,一旦网页过期,必须到服务器上重新传输。
语法:<meta http-equiv="expires" content="Wed, 26 Feb 1997 08:21:57 GMT"/>
注:必须使用GMT的时间格式,或者直接设为0(数字表示多久后过期)
(2) Pragma(cache模式):禁止浏览器从本地计算机的缓存中访问页面内容。
语法:<meta http-equiv="Pragma" content="no-cache"/>
注:网页不保存在缓存中,每次访问都刷新页面。这样设定,访问者将无法脱机浏览。
(3) Refresh(刷新):自动刷新并指向新页面
语法:<meta http-equiv="refresh"content="5; url=http://www.baidu.com/"/>
(其中的5表示5秒后自动刷新并调整到URL新页面。)
(4) Set-Cookie(cookie设定):浏览器访问某个页面时会将它存在缓存中,下次再次访问时就可以从缓存中读取,以提高速度。
语法:<meta http-equiv="Set-Cookie" content="cookievalue=xxx; expires=Wednesday, 21-Oct-98 16:14:21 GMT; path=/">>
注:必须使用GMT的时间格式
(5) Window-target(显示窗口的设定):强制页面在当前窗口以独立页面显示。
语法:<meta http-equiv="Window-target" content="_top"/>
(6) content-Type(显示字符集的设定):设定页面使用的字符集
语法:<meta http-equiv="content-Type" content="text/html;charset=utf-8"/>
【charset:GB2312(简体中文)、BIG5(繁体中文)、iso-2022-jp(日文)、ks_c_5601(韩文)、ISO_8859_1(英文)、UTF-8(世界通用语言编码)】
注:在HTML5中,我们一般都是直接用chartset
属性对字符集进行设定
(7)content-Language(显示语言的设定):显示语言
语法:<meta http-equiv="Content-Language" content="zh-cn"/>
(8)imagetoolbar(图片工具栏):是否显示图片工具栏
语法:<meta http-equiv="imagetoolbar" content="false"/>
HTML5 新增:
(9)X-UA-Compatible(浏览器兼容)
语法:
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
优先使用IE最新版和Chrome<meta http-equiv="X-UA-Compatible" content="IE=6" >
优先使用IE6<meta http-equiv="X-UA-Compatible" content="IE=7" >
优先使用IE7,在IE8版本中使用IE7渲染来避免出错<meta http-equiv="X-UA-Compatible" content="IE=8" >
优先使用IE8(10) Cache-Control(转码声明):用百度打开页面可能会对其进行转码(比如贴广告),以下代码可避免
语法:<meta http-equiv="Cache-Control" content="no-siteapp" />
二、通过媒体查询来设置样式(media query)(设置在style里面,可同时设置多个@media
;也可在<link>
标签中添加media
属性)
参考:https://10.1pxeye.com/responsive-web-design-media-query/
media query 能够跟浏览器沟通,告诉浏览器页面如何呈现。
语法:@media 媒介类型 修饰语 (媒介特征) { … }
修饰语:
- only:仅仅
- not::不包括
- and :连接字符无意义
媒介类型:
- screen:针对屏幕
- print:针对打印
- all:用于所有媒体设备类型
媒介特征:
- device-height | device- width:输出设备的屏幕可见高度 | 宽度
- height | width:输出设备中的页面可见区域高度 | 宽度
- max-device-height | min-device-height | max-device-width | min-device-width:输出设备的屏幕可见最大高度 | 最小高度 | 最大宽度 | 最小宽度
- max-height | min-height | max-width | min - width:输出设备中的页面可见区域最大高度 | 最小高度 | 最大宽度 | 最小宽度
注:max-width在窗口大小改变或横竖屏转换时会发生变化;max-device-width只与设备相关,在窗口大小改变或横竖屏转换时都不会发生变化。
补充:做响应式网站的时候记得至少要加上如下声明:(如果不写这段代码,移动客户端的浏览器真的会以它的1px来显示你设定的1px。最终效果是被缩放的效果,字小小的那种。)
<meta name="viewport" content="width=device-width, initial-scale=1.0">
9、css动画和js动画的实现区别?
参考:
https://www.cnblogs.com/mwxz/p/13206226.html
(1)js动画:
是逐帧动画,是在时间帧上逐帧绘制,且直接对DOM和BOM进行操作。
优点:
- 可以实现一些炫酷的动态效果。
- 可操作性高,能对动画进行开始、暂停、回放等操作。
- 兼容性较好。
缺点:
- 由于逐帧动画的帧序列内容不一样,会增加制作负担,且资源占据比较大。
- 如果帧率过低,会出现帧与帧之间过渡不自然不连贯的情况。
- js是单线程的脚本语言,但js在浏览器主线程运行时,主线程还有其他需要运行的js脚本,样式、计算、布局、交互等任务时,对其干扰线程可能出现阻塞,告辞丢帧情况。
(2)css3(补间动画)
制作简单,只需要第一帧和最后一帧的关键位置即可,两帧之间的内容由Flash自动生成。
优点:
- 用css做动画时,浏览器可以对其进行一些优化,会比js使用更少的占用cpu资源。
- 对于制作一些简单的滑动、翻转比较方便
缺点:
- 对动画的控制比较弱,不能半途对动画进行操作。
- 在做一些炫酷的效果时,其操作比js更冗余。
总结:如果动画只是一些简单的状态切换,滑动等效果,不需要中间的控制过程,css3是比较好的选择,它直接在css文件中就可以实现,不需要引入过多的js库,而一些复杂的客户端界面,动画时,需要对页面进行精准的控制计算,js是不错的选择。
10、css有哪些单位?
- px(像素):相对于设备的长度单位,像素是相对于显示器分辨率而言的。
- em(相对长度单位):相对于当前对象内文本的字体尺寸,如果当前行内文本的字体尺寸未被设置,则相对于浏览器的默认字体尺寸。1em = 1x父元素字体大小(例如:12px)= 12px
特点:em的值并不是固定的;em会继承父级元素的字体大小- rem:根据html根元素的字体尺寸为单位
rem 的优点:只需要设置根目录的大小就可以把整个页面的成比例的调好。
rem 的缺点:
使用rem单位,有时候在小屏幕上,可能会使得字体模糊(放大/缩小的原因)。
使用rem来定义图片、视频尺寸时,可能会使得图片视频模糊。
rem 的兼容性:除了IE8及更早版本外,所有浏览器均已支持rem。- vw:vw 是相对视口(viewport)的宽度而定的,长度等于视口宽度的1%。
假如浏览器的宽度为200px,那么1vw就等于2px(200px/100)。- vh:vh 是相对视口(viewport)的高度而定的,长度等于视口高度的1%。
假如浏览器的高度为500px,那么1vh就等于5px(500px/100)。
-vm:vm 是 CSS3 新增的一个相对单位,相对于视口的宽度或高度中较小的那个。
浏览器高度900px,宽度1200px,取最小的浏览器高度,1 vm = 900px/100 = 9 px。- vmin | vmax:与vm作用一样,是相对于视口的高度和宽度两者之间的最小值或最大值。
11、sass预编译器
参考:Sass文档
12、css和sass的区别
参考:https://www.html.cn/qa/css3/14941.html
sass是css预处理语言,有严格的缩进风格。是对css的扩展,它在css的基础上增加了变量、嵌套、混合、继承、导入等高级功能。
区别:
- sass是css预处理语言,编译后生成css
- sass支持嵌套、继承等高级功能,css不支持
- sass更加优雅,维护更加方便
- sass浏览器不能直接识别解析,需要经过编译器编译
- sass文件后缀名是sass,css的后缀名是css
13、浏览器的模式
- 标准模式:浏览器根据规范呈现页面
- 混杂模式:页面以一种比较宽松的向后兼容的方式显示,混杂模式通常模拟老浏览器的行为以防止老式站点无法工作。
14、减少页面加载时间的方法
参考:
https://blog.csdn.net/weixin_43515797/article/details/109954635(1)减少http请求
- 减少调用其他页面、文件的数量,将多个小文件合并为一个大文件
- 采用精灵图,将多张图片合并成一张大图片。
- 最小化网站上的重定向数量
- 尽量采用get请求。post请求方法的实现需要发送2次http请求,而get只i需要一次。
(2)优化CSS,js
- 压缩合并css样式
- 使用预处理器
(3)文件加载
- 将js文件放在底部,防止白屏现象
- 异步加载script标签,async/defer
- 外部调用css、js文件,因为浏览器本身会对css,js文件进行缓存
(4)采用内容分发网络(CDN)
- 通过多台服务器部署相同的副本,当用户访问时,服务器根据用户跟哪台服务器距离近,来决定哪台服务器去响应请求。
(5)使用服务器渲染
- 客户端渲染:获取HTML文件,根据需要下载js文件,运行文件,生成DOM,再渲染。
- 服务器渲染:服务端返回HTML文件,客户端只需要解析HTML。
优点: 首屏渲染快,SEO(搜索引擎优化)好。
缺点:配置麻烦,增加了服务器的计算压力。(6)使用webpack打包js、scss等
- webpack可以把多种不同的静态资源转换为一个静态文件,这样大大减少页面的网络请求,同时它也可以用来做ES6转码,增加在浏览器中的兼容性。
(7)前端资源动态加载
- 以页面为单位,对路由进行动态加载
- 组件动态加载,对于不在当前视窗的组件,先不加载
- 图片懒加载。对于不在视窗的图片,先不加载。可通过给img标签加上loading=“lazy”开启懒加载模式。
(8)减少重绘重排
(9)压缩文件
- 对js、css、图片等文件进行压缩,通过减少数据传输量从而减少传输时间。
15、单页跳转和多页跳转的区别
(1)单页面应用(SPA):指只有一个主页面的应用,单页面跳转仅刷新局部资源。
优点:
- 用户体验好,快,内容的改变不需要重新加载整个页面,对服务器压力较小
- 前后端分离
- 页面效果会比较炫酷(比如切换页面内容时的专场动画)
缺点:
- 不利于SEO
- 导航不可用,如果一定要导航需要自行实现前进后退。(因为单页面不能用浏览器的前进后退功能)
- 初次加载耗时多
- 页面复杂度提高
(2)多页面(MPA):指一个应用中哟u多个页面,页面跳转时是整个页面刷新的。
16、节流和防抖
(1)节流:在设置的时间段内只能触发一次。
function throttle(fn,delay=100){ //首先设定一个变量,在没有执行我们的定时器时为null let timer = null; return function(){ //当我们发现这个定时器存在时,则表示定时器已经在运行中,需要返回 if(timer) return; timer = setTimeout(()=>{ fn.apply(this,arguments); timer = null; },delay); } }
(2)防抖:当触发函数时,要等到你设置的时间后,函数才会执行。在设置时间内再次触发函数时,会重新计时。
function debounce(fn,delay=200){ let timer = null; return function(){ if(timer) clearTimeout(timer); timer = setTimeout(()=>{ fn.apply(this,arguments); timer = null; },delay); } }
17、跨域
url = 协议+域名+端口(其中有一个不同便是跨域)
跨域是浏览器的一种安全机制,只对浏览器有限制,对服务器没有。
参考:https://segmentfault.com/a/1190000011145364
同源策略的限制:
- Cookie、LocalStorage 和 IndexDB 无法读取
- DOM 和 Js对象无法获得
- AJAX 请求不能发送
解决方案:
(1)通过jsonp跨域:动态插入script标签,给script标签的src属性赋值(url),url里声明将数据传入哪个回调函数中,即:url+?Callback=回调函数名。响应后,数据就会自动保存在回调函数中。只支持get请求,不能进行表单请求。<script> var script = document.createElement('script'); script.type = 'text/javascript'; // 传参一个回调函数名给后端,方便后端返回时执行这个在前端定义的回调函数 script.src = 'http://www.domain2.com:8080/login?user=admin&callback=handleCallback'; document.head.appendChild(script); // 回调执行函数 function handleCallback(res) { alert(JSON.stringify(res)); } </script>
(2)nginx代理跨域
(3)document.domain + iframe跨域
仅限主域相同,子域不同的跨域应用场景。
实现原理:两个页面都通过js强制设置document.domain为基础主域,就实现了同域。
1)父窗口:(http://www.domain.com/a.html)<iframe id="iframe" src="http://child.domain.com/b.html"></iframe> <script> document.domain = 'domain.com'; var user = 'admin'; </script>
2)子窗口:(http://child.domain.com/b.html)
<script> document.domain = 'domain.com'; // 获取父窗口中变量 alert('get js data from parent ---> ' + window.parent.user); </script>
(4)location.hash + iframe
(5)window.name + iframe跨域
(6)postMessage跨域(7)跨域资源共享(CORS)
(8) nodejs中间件代理跨域
(9)WebSocket协议跨域