我是一个双非本的大三在校生,大二开始自学web前端开发。这次我要分享的是我的大三暑期实习前端面试之路(后边有面试宝典哦,努力打造史上最全的那种!)===》运气和实力的游戏:
- 我清楚的记得那是5月18日,我的一个同学说京东零售部门前端招人了让我试一下,当时我十分激动因为之前没有过面试经历。我当时匆忙的做出了我的简历交给了他,他也帮我推了上去,那一刻我才意识到我该努力复习了因为有关面试的知识啥也不会。后续的一周我疯狂的恶补面试的知识,那一周是我人生中过的最快的一周。
- 后续我下载了boss直聘(常用)、实习僧两个软件开始投简历,终于我在5月21日收到了我的第一家面试邀请。真的那种感觉既紧张又激动当时是一个电话面我早早做好了准备等面试官打电话过来。终于在11.00准时接到了电话,面试官上来问我项目说完后开始问Vue的知识先是问了Vue的响应式原理,又问了Vue-Router的原理当时我整个人脑袋直接空白我只说到了表面的含义,更深的却不知道了。后边都是围绕着vue展开问的回答的不是很好,面试官给我的评价是下去需要再了解了解底层的东西。就这样我的第一次面试结束了后来也没有接到电话最终以失败告终,但是这次面试让我受益良多。
- 又投了好多简历,过去了整整6个工作日都没有收到一个电话。在5月27日那天我复习vue的知识的时候“XX医美”给了我第二次面试的机会这次使用的是腾讯会议面试,这次的面试官人很好问的都是前端基础的问题(大概就是些es6的语法和闭包等)后面的面试宝典中会有。这次因为我是暑期实习的问题,实习时间太短虽然通过了面试但还是没有被选上。
- 连续两次的失败导致了我一天的郁闷,我早早回到了宿舍躺下开始深思到底是哪里有问题。想着想着就睡着了😆,第二天起床抹一把脸又是新的一天必须得振作起来。去到教室开始学习后来晚上吃完饭收到了微X的电话约我周六参加笔试,人生第一次参加笔试的机会就这样给了微X😂。很幸运我通过了,后来HR和我约了第一次面试,这次是在腾讯会议视频面试的,面试我的是一个小姐姐她把前端2/3的基础知识都问了个遍。我两聊了有一个小时多,面完我就感觉我过了一天后HR加了我微信通知我二面。可能一面基础问的比较多,二面面试官从开始就一直深挖我的项目。问我有关计算机网络的一些知识,最后问了一个有关100层楼扔玻璃球怎样最快找到它碎的临界值楼层的问题。可能我答的并不是很好第二天我被通知面试没有通过/(ㄒoㄒ)/~~就这样进微X的大好机会就没了,现在回想起来还是很难受就差那么一点点。
- 前边的失败让我找到了自己很多的不足,于是我继续努力去背一些概念性的东西去理解一些源码为啥这样写。手写一些代码和一些算法。6.5日晚上我收到了中科XX的电话,面试官一上来就开始问我技术问题真的让我猝不及防。幸好之前有所准备再加上面试官问的都是些基础的问题所以一面直接就过了,面试官通知我可能会有领导再面我一次让我等电话,后来给我打电话的是一个HR直接和我谈了薪资和入职时间(不是特别满意)。就这样我第一次成功让我的内心有了许多底气,我开始向更大的目标进发继续在面试的道路上越挫越勇。
- 在6.7日晚上7点的时候我接到了我的第5次面试,是电话面试。虽然是电话面试但这次面试让学习到了太多,这次面试的面试官是我见过最好的面试官在我不会的时候会引导我。我实在不会的还会给我认真讲解。因为技术栈不符合他们是React而我目前只是Vue,包括我可能对Git不是太熟练最后并没有选择我。我也很理解因为面试本来就是候选人和公司互相双选的过程。
- 我非常感谢这段时间努力冲刺的我,这一星期的效率是我之前三个星期都比不上的。我的进步神速,努力和运气都是成正比的,6.8日我收到了之前投的诸多大厂中京X的电话是健康部门的前端开发,我非常开心也非常珍惜这次机会,上午11点面试完后一面面试官直接说我过了他问的都是一些前端基础的东西HTML5、CSS3还有一些js的东西,晚上我就收到了二面面试官的电话这次问的是关于项目的问题比较多。es6(必问)和VUE问了很长时间,就这样大概30多分钟结束了我感觉还可以。其实面试过不过自己是可以感觉出来的等到周五我等来了三面面试官的电话,我不知道为啥这次是一个姐姐面试的我,将一些人性、情商、技术的问题穿插在一起问问了大概27分钟。结束后她让我加了微信,我耐心等待结果最终在端午来了后周二收到了京X的offer那个时刻我真的是超开心(阴云转晴!☁)。
- 在等待京X面试期间我还面了海南XX,这家公司面试就很奇怪我前端面试只面试了10分钟就结束了。真的很奇怪而且当天就发了offer后来我拒绝了因为实在是太奇怪了,主要前端就问了两个技术问题因此我推测我去了大概率学不上有用的东西。
- 在京X拿到offer后我因为之前约好了2家公司的面试所以还继续面了猫X和货XX,由于算法不是特别好因此猫X以失败告终,而货XX最终虽然成功但是我经过思考还是不打算去所以在HR给我打电话的时候我就拒绝了。
- 就这样一个月的面试时光结束了,我有幸拿到了offer。路途蜿蜒曲折,还是送给大家一句话任何事情只有努力之后才会知道自己到底行不行!
上边的故事看完下面该上干货了----前端面试宝典(实习,秋招,春招都🆗):
1、布局类(🐷🐷🐷🐷🐷):
- 左右固定中间自适应(5种):
<!-- 浮动布局 --> <section class="layout-float"> <style> html * { margin: 0; padding: 0; } .left-center-right div { min-height: 150px; } .layout-float .left { width: 300px; float: left; background-color: blue; } .layout-float .center { background-color: yellow; } .layout-float .right { width: 300px; float: right; background-color: blue; } </style> <article class="left-center-right"> <div class="left"></div> <div class="right"></div> <div class="center">center</div> </article> </section> <!-- 绝对定位布局 --> <section class="layout-position"> <style> html * { margin: 0; padding: 0; } .layout-position .left-center-right { margin-top: 20px; } .layout-position .left-center-right div { min-height: 150px; position: absolute; } .layout-position .left { width: 300px; left: 0; background-color: blue; } .layout-position .center { left: 300px; right: 300px; background-color: yellow; } .layout-position .right { width: 300px; right: 0; background-color: blue; } </style> <article class="left-center-right"> <div class="left"></div> <div class="center">center</div> <div class="right"></div> </article> </section> <!-- flex布局 --> <section class="layout-flex"> <style> html * { margin: 0; padding: 0; } .layout-flex .left-center-right { display: flex; margin-top: 200px; min-height: 150px; } .layout-flex .left { width: 300px; background-color: blue; } .layout-flex .center { flex: 1; background-color: yellow; } .layout-flex .right { width: 300px; background-color: blue; } </style> <article class="left-center-right"> <div class="left"></div> <div class="center">center</div> <div class="right"></div> </article> </section> <!-- table布局 --> <section class="layout-table"> <style> html * { margin: 0; padding: 0; } .layout-table .left-center-right { width: 100%; display: table; margin-top: 20px; min-height: 150px; } .layout-table .left-center-right div { display: table-cell; } .layout-table .left { width: 300px; background-color: blue; } .layout-table .center { background-color: yellow; } .layout-table .right { width: 300px; background-color: blue; } </style> <article class="left-center-right"> <div class="left"></div> <div class="center">center</div> <div class="right"></div> </article> </section> <!-- grid布局 --> <section class="layout-grid"> <style> html * { margin: 0; padding: 0; } .layout-grid .left-center-right { display: grid; margin-top: 20px; grid-template-columns: 300px auto 300px; grid-template-rows: 150px; } .layout-grid .left { background-color: blue; } .layout-grid .center { background-color: yellow; } .layout-grid .right { background-color: blue; } </style> <article class="left-center-right"> <div class="left"></div> <div class="center">center</div> <div class="right"></div> </article> </section>
- 上下固定中间自适应(4种):
<!-- 绝对定位 --> <section class="layout-postion"> <style> html * { margin: 0; padding: 0 } .top-center-bottom { width: 100%; height: 100%; } .top-center-bottom div { width: 100%; position: absolute; } .layout-postion .top { height: 100px; background-color: blue; top: 0; } .layout-postion .center { background-color: yellow; top: 100px; bottom: 100px; } .layout-postion .bottom { height: 100px; background-color: blue; bottom: 0; } </style> <article class="top-center-bottom"> <div class="top">top</div> <div class="center">center</div> <div class="bottom">bottom</div> </article> </section> --> <!-- flex布局 --> <section class="layout-flex"> <style> html, body, .layout-flex { height: 100%; margin: 0; padding: 0; } .top-center-bottom { display: flex; flex-direction: column; width: 100%; height: 100%; } .layout-flex .top { height: 100px; background-color: blue; } .layout-flex .center { background-color: yellow; flex: 1; } .layout-flex .bottom { height: 100px; background-color: blue; } </style> <article class="top-center-bottom"> <div class="top">top</div> <div class="center">center</div> <div class="bottom">bottom</div> </article> </section> <!-- table布局 --> <section class="layout-table"> <style> html, body, .layout-table { height: 100%; margin: 0; padding: 0; } .top-center-bottom { display: table; width: 100%; height: 100%; } .top-center-bottom div { display: table-row; } .layout-table .top { height: 100px; background-color: blue; } .layout-table .center { background-color: yellow; } .layout-table .bottom { height: 100px; background-color: blue; } </style> <article class="top-center-bottom"> <div class="top">top</div> <div class="center">center</div> <div class="bottom">bottom</div> </article> </section> <!-- grid布局 --> <section class="layout-grid"> <style> html, body, .layout-grid { height: 100%; margin: 0; padding: 0; } .top-center-bottom { height: 100%; display: grid; grid-template-rows: 100px auto 100px; grid-template-columns: 100%; } .layout-grid .top { background-color: blue; } .layout-grid .center { background-color: yellow; } .layout-grid .bottom { background-color: blue; } </style> <article class="top-center-bottom"> <div class="top">top</div> <div class="center">center</div> <div class="bottom">bottom</div> </article> </section>
- 圣杯布局(主区域先显示,两端自适应):
<style> html * { margin: 0; padding: 0; font-size: 16px; text-align: center; } header, footer { background-color: pink; height: 100px; line-height: 100px; } .swipper { height: 300px; line-height: 300px; padding-left: 300px; padding-right: 200px; } .swipper .column { float: left; } .swipper .center { width: 100%; background-color: orange; } .swipper .left { width: 300px; background-color: skyblue; margin-left: -100%; position: relative; left: -300px; } .swipper .right { margin-right: -200px; width: 200px; background-color: green; } </style> </head> <body> <!-- 圣杯布局 如果网卡的话优先展示主区域 float+margin--> <header>首部</header> <div class="swipper"> <div class="center column">中间</div> <div class="left column">左边</div> <div class="right column">右边</div> </div> <footer>尾部</footer> </body>
- 双飞翼布局:
<style> html * { padding: 0; margin: 0; text-align: center; } .column { height: 100px; line-height: 100px; float: left; } .center { width: 100%; background-color: orange; } .center .main { margin-left: 300px; margin-right: 200px; } .left { width: 300px; margin-left: -100%; background-color: skyblue; } .right { margin-left: -200px; width: 200px; background-color: yellow; } </style> </head> <body> <!-- 双飞翼布局 如果网卡的话优先展示主区域 float+margin--> <div class="center column"> <div class="main">中间</div> </div> <div class="left column">左侧</div> <div class="right column">右侧</div> </body>
2、CSS盒模型(🐷🐷🐷🐷🐷):
基本概念:标准模型+IE模型(标准模型和IE模型的区别,CSS如何设置这两种模型,JS如何获取盒模型的宽和高,实例题解释边距重叠,BFC(边距重叠解决方案) )
标准模型:
IE模型:
这两种模型如何进行切换:
3、JS如何获取宽和高(🐷🐷🐷🐷🐷):
- 只能获取内联样式宽和高,外联样式获取不到:
- 只有IE支持,拿到dom渲染完的宽和高:
- 都支持的,拿到dom渲染完的宽和高:
- 计算一个元素的绝对位置(相对于视窗):
4、实例题解释边距重叠-BFC(🐷🐷🐷🐷🐷):
BFC也叫块级格式化上下文
BFC特性:1、在BFC这个元素的垂直方向边距会发生重叠
2、BFC的区域不会和浮动box重叠
3、BFC是一个独立的容器里外元素互不影响
4、计算BFC元素的时候浮动元素会参与计算(清除浮动)
如何创建BFC:float、postion(绝对定位)、display:table/table-cell、overflow:hidden/auto
☆边距重叠时取最大值
BFC的使用场景:
- BFC垂直方向边距会重叠
- BFC元素不会和浮动box重叠:
- 计算BFC元素的时候浮动元素会参与计算:
5、DOM事件类(🐷🐷🐷):
1、DOM事件级别(DOM3增加了一些其它事件如键盘事件):
2、事件模型(鼠标点击后传到页面就是事件流):
3、描述DOM事件捕获的具体流程:
4、Event对象的常见应用:
5、自定义事件:
addEventListener(里的true指的是在捕获阶段触发,false(默认)冒泡阶段触发)
CustomEvent用法:注意传的参数对象要放在detail里
6、计算机网络类(🐷🐷🐷🐷🐷):
计算机网络这一块稍微大一点的厂子都会问的!都会问的!都会问的!都会问的!
都是重点,不想记的混个眼熟也可以xdm
- Https和Http的区别:
Https = Http + SSL(靠证书验证服务器的身份);访问https的网址服务器端会返给客户端一个钥匙和证书,两者发信息的时候服务器证书验证通过后都用各自的钥匙进行数据的解密发送的时候再加密
- http的主要特点:
1.1版本支持一次发送6个http请求,
2.0版本可以无限制发送http请求。 =====》可以告诉后台可以的话使用2.0版本来优化页面
- Http报文的组成部分:
请求报文、请求行:HTTP方法,页面地址,http协议,版本
请求头:key-value值的形式,告诉服务端要什么
空行:遇到空行代表请求头部分已经完了,该解析请求体了
- http方法:
- Post和Get请求的区别:
- Http状态码:
Range代表分批下载
- Http持久连接(keep-Alive):
http持久连接是在1.1版本才开始支持的,1.0版本不支持
- Http的管线化(了解):
基本原理:请求一起打包发过去,响应也一起打包发回来面试官问起管线化的问题来聊的点:
Referer代表的是什么,它可以预防CSRF攻击
- 什么是DNS?
DNS是域名解析系统,最初,由于ip长且难记,通过ip访问网站不方便,所以出现了域名解析系统,将域名转化为对应的ip地址。DNS主要采用了UDP进行通讯,主机向本地域名服务器查询一般递归查询,本地域名向根域名服务器查询采用迭代查询。- 什么是CDN?
访问离你最近的服务器拿文件,没有的话最近的服务器会去原始服务器拿数据,并做一个缓存当用户再次访问最近的服务器会直接拿到缓存。速度会快上很多。
CDN是内容分发网络,尽可能避开互联网上有可能影响数据传出速度和稳定性的瓶颈和环节,使传输内容更快、更稳定。CDN只是对某个具体的域名的加速。
CDN访问的过程(有印象):
1. 当用户点击网站页面上的URL内容,经过本地DNS解析,会将域名的解析权交给CNAME指向的CDN专用DNS服务器。
2. CDN的DNS服务器将CDN的全局均衡设备IP地址返回给用户
3. 用户向CDN的全局负载均衡设备发起请求
4. CDN全局均衡设备根据用户IP地址,以及用户请求的内容URL,选择一台用户所属区域的区域均衡设备,并将请求转发到这台设备。
5. 区域负载均衡设备根据用户IP、请求的URL为用户选择一台 合适的缓存服务器提供内容。
6. 全局负载均衡设备把服务器的IP返回给用户
7. 用户向CDN缓存服务器发起请求,
8. 缓存服务器响应用户请求,将用户所需内容传送到用户终端。- 什么是UDP?
UDP全称用户数据报协议,是传输层协议。具有以下特点:
1. 无连接:发送数据之前不需要建立连接
2. 面向报文:应用层传过来多少数据,原封不动的向下传递
3. 尽最大努力交付:不可靠连接
4. 首部开销较小:首部仅有8个字节
5. 可以实现一对一、一对多、多对多之间的通讯
6. 没有拥塞控制- 什么是TCP?
TCP全称传输控制协议,也是传输层协议。TCP是面向连接的、可靠的字节流服务。具有以下特点:
1. 面向连接的传输层协议
2. 一条TCP连接只有两个端口
3. TCP提供全双工的通信,并且接收端和发送端都设有缓存
4. 面向字节流的服务
5. 可靠传输、流量控制、拥塞控制
- 从输入URL到页面加载完成都发生了什么?
对URL这个网址进行DNS域名解析,得到对应的IP地址
首先在第一步DNS找到IP的过程需要掰扯一下,它首先会去浏览器自身的缓存去找没找到会搜索系统自生的缓存去找还没找到就去hosts里去找。再找不到就只能递归的去域名服务器找。首先去找本地DNS服务器发现没有后会去根服务器去找(也就是点服务器)没找到的话根服务器会返回给它顶级域名的服务器地址(如com服务器),它就会去顶级域名服务器去找还没找到顶级域名服务器告诉它域名服务器所在的地址(也就是你买域名和服务器的那个地址)最后找到后本地服务器会先做一个备份然后在返回给浏览器。
根据这个IP,找到对应的服务器,发起TCP的三次握手
一张图胜过千言万语!建立TCP连接后发起HTTP请求
服务器响应HTTP请求,浏览器得到html代码(首次访问是没有html文件的)
浏览器解析html代码,并请求html代码中的资源(如js、css、图片等)(先得到html代码,才能去找这些资源)
这里就涉及到js的异步加载async和defer了(性能优化)
浏览器对页面进行渲染呈现给用户
先是HTML解析生成DOM树,然后是CSS开始解析生成CSSOM树然后DOM树和CSSOM树进行合并生成Render树再配合Layout树最后进行重绘和重排将页面呈现给用户。
服务器关闭关闭TCP连接(四次挥手)
7、原型链类(🐷🐷🐷🐷🐷):
1、概念:
当访问一个对象的某个属性时,会先在这个对象本身属性上查找,如果没有找到,则会去它的__proto__隐式原型上查找,即它的构造函数的prototype,如果还没有找到就会再在构造函数的prototype的__proto__中查找,这样一层一层向上查找就会形成一个链式结构,我们称为原型链。
原型链:访问一个对象的属性的时候如果为空会去它的原型对象上寻找(_proto_)也就是构造对象的prototype
2、创建对象的几种方法:
字面量方式创建对象,构造函数方式创建对象,Object.create(参数是谁原型对象就指向谁)的方式创建
3、原型链,把这个图看懂就ok了:
4、instanceof方法的原理:
判断一个对象是不是由指的的构造函数new出来的
手写instanceof原理:
只要是原型链上的构造函数都可以被instanceof判断为true
可以通过实例的原型对象的构造函数等不等于其它构造函数来判断是谁产生的实例
5、new运算符:
背后原理:手写一个new
也就是构造函数M里的this不再是空对象了而变成了新的o
8、call\apply\bind的区别(🐷🐷🐷🐷🐷):
bind就是在call的基础上但是他不会立即执行而是返回一个函数给用户
9、面向对象类(🐷🐷🐷):
1、es5中的类和es6中的类+es6中的继承方式:
2、es5中类的继承包括其优缺点都要说清楚:
/* 类的声明 */ // es5中的类 function Animal() { // this = {} this.name = 'name'; // return {} } /* es6中的class类 */ class Animal2 { constructor() { this.name = 'name' } } /* es6中的class继承 */ class Child2 extends Animal2 { constructor() { // super关键字表示调用父类的构造方法,也就是父类constructor中的内容 super() // 如果子类自己的属性和父类一样就会重写父类的属性 如:this.age = "es6" this.name = "child" } // 上边可以简写成: name="child" //什么constructor和super都可以省略 } /* 实例化 */ console.log(new Animal(), new Animal2()); // 重要: /* 继承的本质还是原型链 */ // 1、借助构造函数实现继承(缺点:parent1原型链上的东西并没有被chlid1所继承,只是把Parent1的this指向了Child1上了) function Parent1() { this.name = "parent1" } Parent1.prototype.say = function () {} function Child1() { Parent1.call(this); this.type = "child1" } console.log(new Child1); // 没有继承到say()方法 // 2、借助原型链实现继承 function Parent2() { this.name = "Parent2" this.play = [1, 2, 3] } Parent2.prototype.say2 = function () { console.log(123123); } function Child2() { this.type = "type2" } // 把Parent2的一个实例对象赋值给Child2的原型对象,这样new出来的Child2的实例对象的原型对象(_proto_)就是Parent2 // 缺点:有多个继承的时候改变任意一个的值另一个也会改变(原因:原型链中的原型对象是共用的) s1.__proto__ === s2.__proto__ => true Child2.prototype = new Parent2(); console.log(new Child2()); var s1 = new Child2() var s2 = new Child2() console.log(s1.play, s2.play); s1.play.push(4); console.log(s1.play, s2.play); //[1, 2, 3, 4] [1, 2, 3, 4] // 第三种继承,组合方式上边两种方式的组合 // 缺点:父类的构造函数执行了两次完全没必要 function Parent3() { this.name = "parent3" this.play = [1, 2, 3] } function Child3() { Parent3.call(this) this.type = "child3" } Child3.prototype = new Parent3() var s3 = new Child3() var s4 = new Child3() s3.play.push(4) console.log(s3.play, s4.play); //[1, 2, 3, 4] [1, 2, 3] /* 组合继承的优化1 */ function Parent4() { this.name = "parent4" this.play = [1, 2, 3] } function Child4() { Parent4.call(this) this.type = "child4" } // 不会再执行父级的构造函数 Child4.prototype = Parent4.prototype; var s5 = new Child4() var s6 = new Child4() console.log(s5, s6); // 无法判断实例是有谁构造的 console.log(s5.constructor); /* 组合继承的优化2(完美优化) */ function Parent5() { this.name = "parent5"; this.play = [1, 2, 3] } function Child5() { Parent5.call(this) this.type = "child5" } // 解决无法判断实例是由谁创造的问题 Child5.prototype = Object.create(Parent5.prototype);// 创建中间对象这个中间对象的原型对象是父类的原型对象,但是子类修改原型对象不会影响到父类的原型对象 Child5.prototype.constructor = Child5//解决无法判断实例是谁构造的问题,必须创建中间对象否则会影响到父类的原型对象 var s7 = new Child5() console.log(s7);
9、promise(解决回调地狱es6)(🐷🐷🐷🐷🐷):
先来看一段代码:
<script> let p1 = new Promise(function (resolve, reject) { // resolve 成功 // reject 失败 resolve(1) }) // p1.then(成功的函数resolve,失败的函数reject) // p1.then(function(){},function(){}) p1.then(function (data) { console.log(data); }) </script>
没有那么多嵌套关系是一个链式编程的结果
axios封装原理:
async和await的原理:
promise.all和promise.race知道就好
10、通信类(🐷🐷🐷🐷🐷):
1、什么是同源策略及限制:
源包含协议域名和端口,三者有一种不一样就是跨域。限制就是不是一个源的文档是没有办法操作的。这是一种安全机制
2、前后端如何通信:
3、如何创建Ajax(浏览器兼容性处理是一个加分项):
// 创建Ajax // 浏览器特征检查,兼容性处理 var xhr = XMLHttpRequest ? new XMLHttpRequest() : new window.ActiveXObject('Microsoft.XMLHTTP'); xhr.open("post", "url") // post请求需要修改请求头 xhr.setRequestHeader('Content-Type', 'application/json'); // get请求是 application/x-www-form-urlencoded xhr.send() xhr.onload = function () { if (xhr.status === 200 || xhr.status === 304) { console.log(xhr.reponseText); } }
4、跨域通信的几种方式(重点):
JSONP的原理:给服务器发送callback的名字,在本地创建一个和callback一样名字的函数接收服务器返回来的数据。此处一般都是采用给window注册一个和callback名字一样的全局函数来自动接收数据(window[callback])
Hash跨域的原理:
要获取数据的页面监听hash的变化并且拿到地址中hash的值然后通过特殊处理就可以用了。发送数据的页面在hash后带上要传的值。(通过改变hash但页面不刷新拿到值)
postMessage(html5的标准):
和Hash类似A窗口要发送数据需要调用window下的postMessage方法参数是要传的数据和要跨的地址可以填(*)。然后B窗口监听message事件获取相应的数据
WebScoket:(项目中用到过,心跳机制包括vue怎样使用、window下怎样使用):
// vue中的使用: methods: { initWebpack() {//初始化websocket const wsuri = "ws://XXX.XXX.XXX:8888/ws"; this.websock = new WebSocket(wsuri);//这里面的this都指向vue this.websock.onopen = this.websocketopen; this.websock.onmessage = this.websocketonmessage; this.websock.close = this.websocketclose; this.websock.onerror = this.websocketerror; }, websocketopen() {//打开 console.log("WebSocket连接成功") // 本人进入 var chatMsg = new app.ChatMsg(this.$route.query.myuserId, null, null, null); //构建DataContent var dataContent = new app.DataContent(1, chatMsg, null); this.chat(JSON.stringify(dataContent)); // 打开心跳 timer = setInterval(this.keepalive, 10000); }, websocketonmessage(e) { //数据接收 console.log(e.data, "连接正常") audio.play() var dataConetent = JSON.parse(e.data) let mymessage = {} mymessage.msg = dataConetent.chatMsg.msg mymessage.userphoto = this.myfriendInfo.faceImage.split('/')[0] === 'M00' ? 'http://XXX.XXX.XXX/st/' + this.myfriendInfo.faceImage : this.myfriendInfo.faceImage // this.friendMessageList.push(mymessage) mesageContainer.innerHTML += `<div class="box5"> <img class="touxiang1" src="${mymessage.userphoto}" alt="" /> <div class="wenti"> <div class="wenti1">${mymessage.msg}</div> </div> </div>` }, websocketclose() { //关闭 console.log("WebSocket关闭"); }, websocketerror() { //失败 console.log("WebSocket连接失败"); this.initWebpack() }, chat(msg) { this.websock.send(msg); }, websocketSend() { if (this.input.trim() !== '') { let mymessage = {} mymessage.msg = this.input mymessage.userphoto = this.myuserInfo.faceImage.split('/')[0] === 'M00' ? 'http://123.56.23.31:88/st/' + this.myuserInfo.faceImage : this.myuserInfo.faceImage // this.myMessageList.push(mymessage) var chatMsg = new app.ChatMsg(this.$route.query.myuserId, this.$route.query.friendId, this.input, null); //构建DataContent var dataContent = new app.DataContent(2, chatMsg, null); this.chat(JSON.stringify(dataContent)); // 模板字符串可能不渲染 mesageContainer.innerHTML += `<div class="box3"> <img class="touxiang1" src="${mymessage.userphoto}" alt="" /> <div class="wenti"> <div class="wenti1">${mymessage.msg}</div> </div> </div>` this.input = "" } else { this.$message.fail('输入为空!') this.input = "" } }, // 心跳对象 keepalive() { // console.log("心跳"); //构建对象 var dataConetent = new app.DataContent(4, null, null); //发送心跳 this.chat(JSON.stringify(dataConetent)); } }, destroyed() { this.websocketclose() clearInterval(timer) this.$message("您退出了聊天系统"); }
// 挂载到window下使用: window.CHAT = { socket: null, init:function(){ //判断浏览器是否支持websocket if(window.WebSocket){ //创建websocket 对象 CHAT.socket = new WebSocket("ws://XXX.XXX.XXX:8888/ws"); CHAT.socket.onopen = function(){ console.log("链接建立成功"); }, CHAT.socket.close=function(){ console.log("链接关闭"); }, CHAT.socket.onerror = function(){ console.log("发生异常"); }, CHAT.socket.onmessage = function(e){ console.log("接受消息:"+e.data); var receiveMsg = document.getElementById("receiveMsg"); var html= receiveMsg.innerHTML;//获取本对象原有的内容 //嵌入新的内容 receiveMsg.innerHTML= html + "<br/>"+e.data; } }else{ console.log("您的浏览器不支持websocket协议"); } }, chat:function(){ //获取发送消息框中所输入内容 var msgContent = document.getElementById("msgContent").value; //将客户输入的消息进行发送 CHAT.socket.send(msgContent); } }; CHAT.init();
CORS跨域,一个新型的ajax的api :
CORS为什么会解决跨域问题:浏览器会拦截ajax请求如果是CROS跨域的会在请求头里添加一个origin
fetch(实现CORS):
fetch('http://localhost:6888/test_get',{ method: 'GET', mode: 'cors', }).then(res => { return res.json(); }).then(json => { console.log('获取的结果', json.data); return json; }).catch(err => { console.log('请求错误', err); }) ``` 后端代码相关配置 ``` c.Header("Access-Control-Allow-Origin", "*") c.Header("Access-Control-Allow-Methods", "GET, POST")
11、安全类(🐷🐷🐷):
要求说出中文名称,攻击原理和防范措施
1、CSRF攻击:
首先用户需要在网站A登陆过产生cookie,网站B引诱用户点击后会发送请求到网站A浏览器会自动带上cookie网站A验证通过会返回数据
如何防御:
利用浏览器不会自动携带token来防御
Referer来源拦截服务器判断是不是我站点下的页面
隐藏令牌就是token放在header上
2、XSS攻击:
XSS的攻击原理:浏览器向服务器请求的时候被注入脚本攻击 分成三种类型 反射型(非持久型), 存储型(持久型), 基于DOM
XSS的防御措施:1. 输入过滤 2. 输出过滤 3. 加httponly 请求头 锁死cookie
12、算法类+一些api的应用(🐷🐷🐷):
可以问面试官,实在不会可以写伪代码,算法不是一下可以速成的需要一朝一夕的积累。力扣多刷题吧。我这里列出几个比较常见的
1、splice的妙用:
2、sort方法:
3、排序:
快速排序:
function quick(ary) { // 4、递归出口当传过来的数组遍历到只剩一项时就好了 if (ary.length <= 1) { return ary } // 1、把中间值的索引拿出来 let middleIndex = Math.floor(ary.length / 2) // 2、注意要拿出值来复制:ary.splice(middleIndex, 1)[0]不能直接给地址 let middleValue = ary.splice(middleIndex, 1)[0] // 开始比较比中间大的放左边数组,比中间小的放右边数组 let leftArr = [] let rightArr = [] ary.forEach(item => { item > middleValue ? rightArr.push(item) : leftArr.push(item) }) // 3、递归调用 return quick(leftArr).concat(middleValue, quick(rightArr)) } let arrQuick = [160, 12, 8, 24, 6, 33, 44] console.log(quick(arrQuick));
冒泡排序:
// 数字比较的轮数 => length-1 for (let i = 0; i < arr.length - 1; i++) { // 不用和自己比,-1 再把比较好的减去-i for (let j = 0; j < arr.length - 1 - i; j++) { if (arr[j] > arr[j + 1]) { let arrTemp arrTemp = arr[j] arr[j] = arr[j + 1] arr[j + 1] = arrTemp } } }
4、向上取整,向下取整、四舍五入:
Math类中提供了三个与取整有关的方法:ceil、floor、round,这些方法的作用与它们的英文名称的含义相对应。
例如,ceil的英文意义是天花板,该方法就表示向上取整,Math.ceil(11.3)的结果为12,Math.ceil(-11.3)的结果是-11;floor的英文意义是地板,该方法就表示向下取整,Math.floor(11.6)的结果为11,Math.floor(-11.6)的结果是-12;
最难掌握的是round方法,它表示“四舍五入”,算法为Math.floor(x+0.5),即将原来的数字加上0.5后再向下取整,所以,Math.round(11.5)的结果为12,Math.round(-11.5)的结果为-11。
13、TS语法拓展(🐷🐷🐷):
装饰器(项目中使用,在编译阶段执行):
14、cookie,获取和设置(🐷🐷🐷):
console.log("开始", document.cookie); document.cookie = "username=ljc" document.cookie = "password=123" console.log("设置"); console.log("获取", document.cookie);
15、渲染机制(🐷🐷🐷🐷🐷):
1、什么是DOCTYPE作用是什么:
大白话就是DOCTYPE通知浏览器用的是什么DTD,DTD就是告诉浏览器我是什么文档类型,浏览器再用相应的引擎渲染
4.0版本是传统和严格模式(不包括弃用的元素)
2、浏览器的渲染过程:
浏览器获取到服务器传过来的HTML文件后进行解析生成DOM树,后来收到CSS文件后解析生成CSSOM树DOM树和CSSOM树进行合并生成Render树最后浏览器根据layout树进行第一次的重绘重排最终展示给用户。
3、重排Reflow(回流):
4、重绘Repaint:
创建一个基础节点,把要渲染的节点都放在基础节点里最后提交一次基础节点就可以减少Repaint
Tip:重排必定会引发重绘,但重绘不一定会引发重排。重绘重排的代价:耗时,导致浏览器卡慢可使用document.createDocumentFragment();一次性加入节点避免多次操作dom
5、js运行机制:
(1)一个时间内执行一个任务就是JS的单线程
(2)任务队列:同步任务先执行,异步任务会挂起等待执行。异步任务的放入时间和执行时间。说白了就是在运行栈里的同步任务没有全部执行完的时候异步任务待的地方就是任务队列。
(3)Event Loop(事件循环):
(4) 宏任务与微任务
(宏观Task) setTimeout, setInterval , requestAnimationFrame, I/O
(微观任务) process.nextTick, Promise, Object.observe, MutationObserver
先同步 再取出第一个宏任务执行 所有的相关微任务总会在下一个宏任务之前全部执行完毕 如果遇见就先微后宏.
运行栈执行的是同步任务,浏览器的timer模块会把setTimeOut拿走时间到了会放到任务队列中。当运行栈空了浏览器会把任务队列的任务拿到运行栈执行
16、页面性能(🐷🐷🐷🐷🐷🐷🐷):
考到这个的时候可以这样答:我认为前端性能优化是一个很大的话题,我会从下面几点开始说明(后边的解决办法)。
1、异步加载:
动态脚本加载指的是用createElement创建script脚本append到页面中,defer和async加在script标签里就可是script的属性
2、浏览器缓存:
强缓存:直接使用本地缓存不问服务器了
Expires:表示绝对时间,服务器下发。但是客户端时间与服务器时间可能不一样
Cache-Control:表示相对时间,不管服务器时间。相对于客户端3600秒之内不会请求服务器,都会直接从浏览器拿缓存
如果两个服务器都下发了则以后者为准
协商缓存:问服务器要不要用本地的缓存
Last_Modified(服务器下发的时间),if-Modified-Since(浏览器带的询问服务器的时候带问服务器资源有没有发生变化),他两共用一个值
Etag (服务器下发的值) if-None-Match
3、图片或静态资源优化:
尽量使用webp格式的图片,图片使用熊猫站压缩打包,图片使用懒加载。对于纯色系小图标可以使用 iconfont 来解决。对于一些彩色的小图片可以使用雪碧图(把所有小图片拼接到一张大图片上 并使用 background-position 的 CSS 属性来修改图片坐标 )可以使用webpack进行文件压缩。使用base64位格式的图片。
4、网络传输加速:
使用CDN加速CDN 服务器就是在你家门口放一台服务器,把所有的静态资源都同步到你家门口这台服务器上,以后只要你访问这个网站,都直接从这台服务器上下载静态资源。
Http1.1 请求:对于同一个协议、域名、端口,浏览器允许同时打开最多 6个 TCP 连接(最多同时发送 6个请求) Http2.0: 引入了多路复用的机制,可以最大化发送请求数量。 所以在支持的情况下尽量使用Http2.0进行数据传输。
如果是node的服务器可以使用gzip压缩优化传输
17、错误监控(🐷🐷🐷):
这一块大家了解就好,大神可以多看看
捕获方式:
object.onerror是在冒泡阶段!Error是在捕获阶段
通过performance.getEntries().forEach(item => {console.log(item.name)})和document.getElementByTagName('要判断的标签')两者之间的数量来判断有几个资源没有加载成功
h5离线存储manifest:
HTML5提出的一个新的特性:离线存储。通过离线存储,我们可以通过把需要离线存储在本地的文件列在一个manifest配置文件中,这样即使在离线的情况下,用户也可以正常看见网页。(404页可以用这个做)
2 在根目录 新建文件 cache.manifest 并写上对应代码 ``` CACHE MANIFEST #v0.11 CACHE: js/app.js css/style.css NETWORK: resourse/logo.png FALLBACK: / /offline.html ```
18、作用域和作用域链+函数闭包(🐷🐷🐷🐷🐷🐷):
函数闭包:一个函数和他周围(上下文)绑定在一起的组合,函数套函数的形式
函数柯里化(参数复用)--没被考过,,ԾㅂԾ,,:采用闭包的形式进行参数的复用。
19、防抖节流(🐷🐷🐷🐷🐷🐷):
防抖就是一定时间内将函数的执行次数变成一次(setTimeOut,时间内判断有没有定时器没有就开一个有就清除掉(搜索框))
节流就是一定时间内触发函数,不是一点就触发(lock锁的方式可以(轮播图的按钮))// 手写防抖 function debounce(callback, times) { let timer = null; return function (...args) { if (timer) { clearTimeout(timer) } timer = setTimeout(() => { callback.apply(this, args) }, times) } } let fun11 = debounce(() => { console.log(123) }, 2000) fun11()
20、深拷贝浅拷贝(🐷🐷🐷🐷🐷🐷):
简单数据类型在栈中存的就是值,复杂数据类型在栈中存的就是数据的地址,真正的数据在堆中。
浅拷贝就是直接把一个对象的地址赋值个另外一个对象,其中一个对象中的值改变另外一个对象的值也会改变
深拷贝就是在堆中再开辟一块空间存放两个对象在栈中存放的地址不一样两个对象就互不影响
1、第一种方法:JSON.parse(JSON.stringify(obj1)) 存在的问题:对象里有函数的话就没有了(函数无法拷贝)正则也无法拷贝 undefined无法拷贝 优点:二级以下也可以实现深拷贝
2、第二种方法:Object.assign(要拷贝到哪个对象,被拷贝的对象) 优点:函数,正则,undefined都可以拷贝缺点:里边的对象只能实现浅拷贝.
3、采用扩展运算符···进行深拷贝
let obj = { name: "Wawa", age: 13, gender: "female" }; let obj1 = {...obj}; obj1.height = 165; console.log(obj);//{name: "Wawa", age: 13, gender: "female"} console.log(obj1);//{name: "Wawa", age: 13, gender: "female", height: 165}
用扩展运算符对数组或者对象进行拷贝时,只能扩展和深拷贝第一层的值,对于第二层极其以后的值,扩展运算符将不能对其进行打散扩展,也不能对其进行深拷贝,即拷贝后和拷贝前第二层中的对象或者数组仍然引用的是同一个地址,其中一方改变,另一方也跟着改变。
4、采用for in的方式进行循环递归的深拷贝:
但是缺点就是对象里有函数的话就没有了(函数无法拷贝)正则也无法拷贝 undefined无法拷贝。优点是可以拷贝多层。
function deepClone(obj){ let objClone = Array.isArray(obj)?[]:{}; if(obj && typeof obj==="object"){ for(key in obj){ if(obj.hasOwnProperty(key)){ //判断ojb子元素是否为对象,如果是,递归复制 if(obj[key]&&typeof obj[key] ==="object"){ objClone[key] = deepClone(obj[key]); }else{ //如果不是,简单复制 objClone[key] = obj[key]; } } } } return objClone; }
21、杂项小知识点复习也很重要哦(🐷🐷🐷🐷🐷🐷):
基本数据类型:
CSS单位补充(rpx为小程序单位px单位的一半):
undefind和null的区别:
null是一个表示"无"的对象(空对象指针),转为数值时为0;
undefined是一个表示"无"的原始值,转为数值时为NaN(是数值类型但不是数字 )。
移动端touches:
数组扁平化(手写实现也很重要):
function flatten(arr) { return arr.reduce((result, item)=> { return result.concat(Array.isArray(item) ? flatten(item) : item); }, []); }
媒体查询:
call、apply、bind的区别(手写):
// 手撕 javascript var obj = { a: 1, b: 2 } var fun = function () { console.log(this.a); console.log(arguments); } Function.prototype.myCall = function () { var callObj = Array.prototype.shift.call(arguments) callObj.fun = this callObj.fun(...arguments) delete callObj.fun } Function.prototype.myApply = function () { var callObj = Array.prototype.shift.call(arguments) callObj.fun = this callObj.fun(arguments) delete callObj.fun } Function.prototype.myBind = function () { var callObj = Array.prototype.shift.call(arguments) var args = arguments var that = this return function () { that.call(callObj, ...args, ...arguments) } } fun.myCall(obj, 1, 2, 3) fun.myApply(obj, [1, 2, 3]) let fun1 = fun.myBind(obj, 11, 22, 33) console.log(fun1("asd"));
数组的api常见总结:
every()是对数组中的每一项运行给定函数,如果该函数对每一项都返回true,则返回true。
some()是对数组中的每一项运行给定函数,如果该函数对任一项返回true,则返回true。
js为什么会阻塞渲染:
因为浏览器是从上到下渲染的,遇到script标签会阻塞下边代码的运行,可以使用defer和async解决
判断是不是数组(全都需要掌握):
javascript instanceof //arr instanceof Array === arr.__proto__ === Array.prototype Array.isArray(arr) Object.prototype.toString.call(data) //啥也能判断 a.constructor === Array;//true
线程与进程的区别(了解):
首先进程就是一个程序加上线程加上状态的组合,比如浏览器就是一个进程,里边有许多线程有渲染页面的有请求数据的。进程在执行过程中拥有**独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
Tcp和Udp的区别(需掌握):
常见的数据结构(大厂必备):
CSS隐藏元素 display、visibility、opacity的区别:
src和href的区别:
变量提升的猫腻:
jquery的相关问题(看文档就行)
WebPack相关复习:
DOMContentLoaded、ready(jquery的方法)、load事件的区别:
内存泄漏、垃圾回收机制:
因为变量一直被引用着得不到释放所以会造成内存泄漏 ==》setTimeOut第一个参数为字符串和定时器一直开着都会造成内存泄漏,对象之间引用、死循环、直接给变量赋值但未定义都会造成内存泄漏
垃圾回收机制的策略:标记清除法,引用计数法
闭包的使用场景:
setTimeout传递的第一个参数不能带参数通过闭包可以实现传参的效果,封装私有变量
meta标签的视口viewport:
让视口和宽度一样
Scss和Less:
&表示父节点,选择器可以嵌套,$可以定义公共变量在下边使用
node.js文件遍历:
css垂直居中(特殊的,都需掌握):
可以使用margin负的宽的一半和margin负的高的一半实现垂直居中,还可以使用 transform: translate(-50%,-50%);实现垂直居中。
this的指向:
默认是在window下,谁调用的则this指向谁
箭头函数:
普通函数只要函数独立调用this指向的就是window否则就是谁调用指向谁,箭头函数没有this用的是上一级作用域的this
滑动窗口:
HTML的空标签:
meta标签的属性:
==和===的区别:
以上内容虽然小而且杂但是很重要,大家需要认真食用!!!!
22、Vue部分面试题--重要!(🐷🐷🐷🐷🐷🐷):
1、父子组件或者子子组件之间传值:
父 子 传值 使用props接收值,使用$emit发送。
子 父 传值 父亲写事件函数 子 $emit触发 传值父使用对应的事件名接收。
兄弟传值 $bus 中转站,就是再写一个js里边new一个vue的实例两个子组件都导入这个js文件
发送一方使用$emit发送接受一方使用$on接收。
如果组件之间 关系很远 是很多组件都要用的值则使用vuex
vuex 就是一个全局状态数据管理 简单来说 他的数据类似全局变量 哪个组件都可以使用
2、Vuex的数据流转(重要):
首先是state它是存放数据的地方获取的方法一般为this.$store.state如果较为常用的话可以使用...mapStates来获取相应的值,其次是mutation他可以用来修改state的值用commit触发或者直接导入...mapMutations使用,还有actions负责获取 处理数据(如果有异步操作必须在action处理 再到mutation), 提交到mutation进行状态更新使用dispatch进行触发。还有getter它不会修改store中的原数据,只会包装加工原数据,类似Vue的计算属性。再者还有module当你要用vuex管理的数据较为复杂且多的话可以使用vuex模块化module管理。
modules(模块化)来为我们的状态树分隔成不同的模块,每个模块拥有自己的state,getters,mutations,actions;而且允许每个module里面嵌套子module;如下: store ├── index.js # 我们组装模块并导出 store 的地方 ├── actions.js # 根级别的 action ├── mutations.js # 根级别的 mutation ├── state.js # 根级别的 state └── modules ├── module1.js # 模块1的state树 └── module2.js # 模块2的state树 每个vuex子模块都可以定义 state/mutations/actions 如果 module1 中定义了 loginMutation, module2中也定义了 loginMutation, 此时, mutation就冲突了如果不想冲突, 各个模块管理自己的action 和 mutation ,需要 给我们的子模块一个 属性namespaced: true
3、封装组件(了解):
首先组件就是一个单位的HTML结构 + 数据逻辑 + 样式的 操作单元 ,而封装组件就是传递不同的参数让对应的组件实现功能而且可以复用。
4、为什么组件要求必须是带返回值的函数?(了解):
我们希望组件内部的数据是相互独立的,且互不响应,所以 采用 return {}每个组件实例都返回新对象实例的形式,保证每个组件实例的唯一性。
5、使用Proxy代理跨域:
6、Vue中的watch如何深度监听某个对象(会):
2. 启用深度监听方式 export default { data () { return { a: { b: { c :'张三' } } } }, watch: { a: { deep: true // deep 为true 意味着开启了深度监听 a对象里面任何数据变化都会触发handler函数, handler(){ // handler是一个固定写法 } } } }
7、Vue keep-alive使用:
keep-alvie出现了, 可以帮助我们缓存想要缓存的组件实例, 只用用keep-alive 包裹你想要缓存的组件实例, 这个时候, 组件创建之后,就不会再进行 销毁, 组件数据和状态得以保存keep-alive包裹的组件 都获取了另外两个事件 --如果缓存组件需要重新获取数据**
唤醒 activated重新唤醒休眠组件实例时 执行
休眠 deactivated组件实例进入休眠状态时执行如果是针对 组件容器 router-view 这个组件进行的缓存, 一般的策略是在路由的元信息 meta对象中设置是否缓存的标记, 然后根据标记决定是否进行缓存
<div id="app"> <keep-alive> <!-- 里面是当需要缓存时 显示组件的 router-view--> <router-view v-if="$route.meta.isAlive" /> </keep-alive> <!-- 外面是不需要缓存时 --> <router-view v-if="!$route.meta.isAlive" /> </div>
8、$router和$route的区别:
9、刷新页面的几种方式(location的属性):
vue是this.$router.replace()('当前路由')、this.$router.go(0)
10、vue的双向数据绑定原理是什么:
简单概述 : 通过Object.defineProperty 完成对于数据的劫持, 通过观察者模式, 完成对于节点的数据更新
<!-- 简单数据双向绑定 --> <input type="text" id="username"> <br> 显示值:<span id="uName"></span> <script> var obj = {} Object.defineProperty(obj, "username", { get: function () { console.log("取值"); }, set: function (val) { console.log("设置值"); document.getElementById("uName").innerText = val } }) document.getElementById("username").addEventListener("keyup", function () { obj.username = event.target.value }) </script>
````此处等我更新原理代码````
11、页面刷新了之后vuex中的数据消失怎么解决(此处说一下缓存数据的方式``常考``):
vuex数据位于内存, 页面的刷新重置会导致数据的归零,也就是所谓的消失, 本地持久化可以解决这个问题.本地持久化用到的技术也就是 本次存储 sesstionStorage(会话缓存窗口关闭后缓存即消失,可以使用window.sessionStorange.setItem('key','value')设置,使用window.sessionStorange.getItem(key)获取) 或者 localStorage(本地长期存储,窗口关闭也会在设置获取方法同上)。
12、vue-router的传值方式:
最简单的就是url传值, url传值又两种, params 和 query参数传值,params传值 是指的动态路由传值
> { path: '/user/:id' } // 定义一个路由参数 > <router-link to="/user/123"></router-link> // 传值 > /user/123 > '/user/:id' ---123 就是 id > this.$route.params.id // 取值 专门获取 :id 这种参数 params 参数 > > > params传值 通过$router.push({name:"xxx",params:{detailId:"xxx"}}) > > this.$router.push({ name: "ArticleDetail", params: { detailData: JSON.stringify(this.articelList[index]) } }) > // 接收 > let index = JSON.parse(this.$route.params.detailData) > > > query传值,指通过?后面的拼接参数传值 > > > { path: '/user' } // 定义一个路由参数 > <router-link to="/user?id=123&name=zs"></router-link> // 传值 > this.$route.query.id // 取值 获取 ?后面的参数 query参数 查询字符 > this.$route.query.name --- zs
13、前端鉴权一般思路:
我们可以 在axios的 请求拦截器 里面 配置 token
有些页面 需要登录才能看 我们也可以用路由导航守卫 router.beforeEach 判断 token
14、默认插槽,作用域插槽,具名插槽:
子组件定义一个<slot></slot>标签的话父组件使用子组件的时候可以在中间插入任意值
父组件:
子组件:
v-slot以及作用域插槽 子组件: <template> <div> <div class="container"> <header> <!-- 我们希望把页头放这里 --> <slot name="header"></slot> </header> <section> v-slot组件 </section> <footer> <!-- 我们希望把页脚放这里 --> <slot name="footer" :msg="msg"></slot> </footer> </div> </div> </template> <script> export default { data() { return { msg:'vsolt作用域插槽组件' } }, created() {}, mounted() {}, methods: {} } </script> 父组件: <template> <div id="inforCategory-warp"> <vsolt> <template v-slot:header> <h2>slot头部内容</h2> </template> <p>直接插入组件的内容</p> <template v-slot:footer="scope"> // 重点 <h2>slot尾部内容<span style="color:red">{{scope.msg}}</span></h2> </template> </vsolt> </div> </template> <script> import vsolt from './v-slot' export default { name: 'inforCategory', components: { vsolt, }, data(){ return{ msg:'具名插槽信息', msg2:'v-slot' } } } </script>
15、Vue路由的两种模式:
16、Vue的计算属性和watch区别所在:
17、vue图片懒加载 —— vue-lazyload的使用:
main.js 中全局引入: import VueLazyLoad from 'vue-lazyload' Vue.use(VueLazyLoad, { preLoad: 1, error: require('./assets/img/error.jpg'), loading: require('./assets/img/homePage_top.jpg'), attempt: 2, }) ``` ```javascript lazyloadDemo.vue(页面中)使用: <!-- img中使用图片懒加载。 v-lazy代替v-bind:src --> <img v-lazy="item" alt="" style="width: 768px;"> <!-- 背景图中使用图片懒加载。 v-lazy:background-image = "" --> <li v-for="(item,index) in imgList" v-lazy:background-image="item"></li>
23、Git操作(拓展知识)--重要!(🐷🐷🐷🐷🐷🐷🐷):
git我这里讲一下具体该怎样用,学以致用嘛。
首先如果是脚手架创建的项目默认会为我们初始化本地git仓库(.git文件夹),如果我们自己创建的话是没有的需要在命令行面板敲git init 初始化一个git仓库出来。
第二步就是创建我们的远程仓库了一般用的比较多的就是gitee和github,创建好远程仓库后会有两行命令我们复制进命令提示面板执行即可(公司项目根本不需要我们创建仓库),当然也可以按照它的提示以命令提示行的方式远程创建仓库。如下图:
仓库创建好配置完了我们就需要知道几条命令并且要熟记于心(就用大白话讲了):
1、git status 查看本地工作区有变动的文件;
2、git branch 查看本地目前处于哪个分支进行开发;
3、git checkout XXX 切换到XXX分支;
4、git checkout -b XXX 创建并切换到XXX分支;(git branch XXX 创建XXX分支)
5、git branch -d XXX 删除XXX分支
6、git add . 添加所有变动文件到暂存区
7、git commit -m "XXX(指的是对本次提交的描述)" 提交暂存区文件到本地仓库
8、git push 推送本地仓库文库到远程仓库(在这之前需要配置好远程仓库用户名和邮箱),第一次执行可能会出现问题按照给定的提示复制对应给出的提示命令执行即可。
9、git config --global user.name "username" git config --global user.email "email" 配置用户名和邮箱
10、git pull 更新远程仓库文件到本地对应的分支下。
11、git log 查看提交的日志主要为了查看提交的唯一标识方便回滚代码
12、git reset --hard XXX 回滚到版本号标识为XXX的版本
这就是我在实习的时候能用到的几个命令了,虽然有点大白话可能与专业术语有些冲突但这是我自己理解的意思。如有问题希望大家指正。
写到这已经差不多总结完了,后续秋招完我会补充对应的学习路线和其它的知识的主要有webpack和node的东西(目前还不是很懂,有点菜😂),有的是手打有的是总结上去的难免会出现错误还希望大家多多谅解并在评论区指出。加油吧,共勉~!