先简单做个自我介绍
您好,我叫XX,统招本科学历,毕业后从事前端工作三年了(不问的话尽量不提专业,问的话就说不喜欢自己的专业,毕业之前培训了半年)这三年一直在XXX公司工作,公司里面前期项目是js,jquery配合node.Js的项目,后期转为了vue项目,目前公司发展不太景气,所以决定出来找一些新的机会。
公司是自研项目还是外包甲方的项目
都是外包的项目
为什么你大学学的护理,但是却来做程序员了呢?
因为上大学时候是家长给我选的专业
大学期间发现自己不喜欢这个专业,就去培训班培训了web前端
后来一毕业就找了前端的工作
你这个新辉传媒有限公司在哪啊?规模怎么样?
公司在塘沽,塘沽站附近。
规模大概有十几个人左右,有四五个人从事开发工作,两个前端,三个后端。
参加过的这些项目是独立负责的吗?参与到什么程度?
开始做项目的时候是有项目经理负责带着一起做,做过一个项目之后就开始独立负责项目了,都是从项目的最开始到项目的结束一直在跟进。
简单介绍一下你简历中做过的这个统计平台项目吧,做了哪些模块?各个模块中都做了什么功能?
这个统计平台是针对滨海交管局的定制化项目 ,实现了用户对具体某个时间段 ( 日 ,月 ,季 ,年) 相关统计报表的查看 工作内容
里面的主要模块有日报查询、月报查询、季报查询、数据统计这个四个模块
其实主要实现的功能都一致,都是对后端的数据进行可视化展示
用的技术是Luckysheet,将他二次封装了一下,不同的模块调用的都是同一个方法
将查到的数据返回给luckysheet表单,并能够通过用户在前端的修改,同步修改后台的数据
然后数据统计模块是用了echarts将日月年报三个规格的数据以图表方式展示。
简单介绍一下你简历中做过的这个松华智能工厂项目吧,做了哪些模块?各个模块中都做了什么功能?
该项目主要有工厂器具台账 ,检测台账 ,固定资产投资 ,人员管理这些模块
由驾驶舱和填报系统两个子 系统构成 ,
驾驶舱主要通过可视化界面直观展示该工厂各模块数据
填报系统可增删改查各模块数据
我的工作内容 :
1、使用echarts将折线图 ,柱图和饼图封装成项目通用组件
2、全局样式文件中基于element-ui封装两个组件样式类 ,分别用于驾驶舱和填报系统
3.首页展示日历、最新公告、帮助链接、便捷导航模块
4.公司组织架构以树形结构展示并实现部门的增删改查功能
物品领用柜这个是H5的项目吗?各个模块中都做了什么功能?
这个项目主要用于企业员工购买工作用品
有轨道柜商品购买和称重柜商品购买,
其中轨道柜中各个商品通过H5展示,员工可选择购买
称重柜则需要员工主动取商品完成购买
主要负责整个项目的搭建
1、使用 Vant 组件库完成项目页面搭建
2、使用媒体查询配合rem实现适配不同分辨率手机
3、在导航守卫中调用微信授权工具中的方法完成微信授权登录功能
4、获取微信签名以及使用微信的 api 实现微信支付功能
5、配合后端完成各页面的功能逻辑
6、配合设备端与测试完成功能的验证
H5的新特性都有什么?
更加语义化的元素。 article、footer、header、nav、section
本地化储存。 localStorage 和 sessionStorage
离线应用,离线缓存。 manifest
拖曳以及释放的api。 Drag and drop
媒体播放。 video 和 audio
增强表单控件。 calendar、date、time、email、url、search
地理位置。 Geolocation
多任务。 webworker
全双工通信协议。 websocket
历史管理 history
跨域资源共享(CORS) Access-Control-Allow-Origin
页面可见性改变事件 visibilitychange
跨窗口通信 PostMessage
Form Data 对象
绘画:canvas
小李的温馨提示:
说出来
更加语义化的元素。 article、footer、header、nav、section
本地化储存。 localStorage 和 sessionStorage
拖曳以及释放的api。 Drag and drop
媒体播放。 video 和 audio
这几个就差不多。别的也要眼熟
扩展: 如何使用 Vant 组件库完成项目页面搭建
1.引入依赖
<!-- 引入 Vant 的 CDN -->
<link rel="stylesheet" href="https://unpkg.com/vant@next/dist/vant.css">
<script src="https://unpkg.com/vue@next"></script>
<script src="https://unpkg.com/vant@next"></script>
2.引入需要的组件
import { Tab, Tabs, Cell, CellGroup, Input } from 'vant';
3.引入样式
@import '~vant/lib/index.css';
4.使用组件
<template>
<div>
<van-tabs v-model:selected="active">
<van-tab title="选项卡1">内容1</van-tab>
<van-tab title="选项卡2">内容2</van-tab>
<<van-tab title="选项卡3">内容3</van-tab>
</van-tabs>
<van-cell-group>
<van-cell title="输入框">
<van-input v-model:value="input" placeholder="请输入"></van-input>
</van-cell>
</van-cell-group>
</div>
</template>
扩展:如何在导航守卫中调用微信授权工具中的方法完成微信授权登录功能?
1.导入微信授权登录工具,并定义跳转到登录页面的路由:
import authorize from '@/utils/authorize'; // 引入微信授权登录工具
// ...
const routes = [
{
path: '/login',
component: Login,
name: 'Login'
},
// ...
]
2.在 beforeEach 导航守卫中,判断用户是否已经登录:
router.beforeEach((to, from, next) => {
const token = localStorage.getItem('token');
if (to.meta.requiresAuth && !token) {
next({
path: '/login',
query: { redirect: to.fullPath } // 将要访问的地址作为参数传递给登录页面
});
} else {
next();
}
});
3.如果用户未登录,则跳转到登录页面。在登录页面中,可以使用微信授权登录工具中的方法完成微信授权登录:
<template>
<div>
<button @click="login">微信登录</button>
</div>
</template>
<script>
import authorize from '@/utils/authorize'; // 引入微信授权登录工具
export default {
name: 'Login',
methods: {
login() {
authorize(() => {
// 操作成功处理的回调函数
this.$router.push('/');
}, () => {
// 操作失败处理的回调函数
alert('授权失败,请重新点击授权');
});
}
}
}
</script>
4.在微信授权登录成功后,可以将用户 token 存储在 localStorage 中,并重定向到登录前要访问的页面。
扩展: 如何获取微信签名以及使用微信的 api 实现微信支付功能?
1.在微信公众平台或开放平台上创建应用,并获取 appid 和 appsecret。
2.使用 appid 和 appsecret 调用微信接口获取 access_token。
3.使用 access_token 调用微信接口获取 jsapi_ticket。
4.将获取到的 jsapi_ticket、随机字符串、时间戳和当前页面的 URL 拼接为一个字符串。
5.对拼接后的字符串进行 SHA-1 签名。
下面是获取微信签名的代码示例:
// 生成随机字符串
function nonceStr(len) {
var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var maxPos = chars.length;
var nonceStr = '';
for (var i = 0; i < len; i++) {
nonceStr += chars.charAt(Math.floor(Math.random() * maxPos));
}
return nonceStr;
}
// 获取微信签名
function getWXSign() {
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET', false);
xhr.send();
var res = JSON.parse(xhr.response);
var accessToken = res.access_token;
xhr.open('GET', 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=' + accessToken + '&type=jsapi', false);
xhr.send();
var res = JSON.parse(xhr.response);
var jsapiTicket = res.ticket;
var noncestr = nonceStr(16);
var timestamp = String(Math.floor(new Date().getTime() / 1000));
var url = window.location.href.split('#')[0];
var str = 'jsapi_ticket=' + jsapiTicket + '&noncestr=' + noncestr + '×tamp=' + timestamp + '&url=' + url;
var sha1 = CryptoJS.SHA1(str).toString();
return {
appId: 'YOUR_APP_ID',
timestamp: timestamp,
nonceStr: noncestr,
signature: sha1
};
}
获取微信签名后,可以使用微信的 API 实现微信支付功能。
以下是使用 JavaScript 使用微信 API 实现微信支付功能的代码示例:
// 发起微信支付请求
function wxPay() {
var xhr = new XMLHttpRequest();
xhr.open('POST', 'https://yourserver.com/orders', false);
xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
xhr.send(JSON.stringify({
body: '商品描述',
out_trade_no: Date.now().toString(),
total_fee: 100, // 订单总金额(单位为分)
openid: 'YOUR_OPENID'
}));
var order = JSON.parse(xhr.response);
var noncestr = nonceStr(16);
var timestamp = String(Math.floor(new Date().getTime() / 1000));
var prepay_id = order.prepay_id;
var str = 'appId=' + 'YOUR_APP_ID' + '&nonceStr=' + noncestr + '&package=prepay_id=' + prepay_id + '&signType=MD5&timeStamp=' + timestamp + '&key=' + 'YOUR_SECRET_KEY';
var paySign = CryptoJS.MD5(str).toString().toUpperCase();
wx.chooseWXPay({
timestamp: timestamp,
nonceStr: noncestr,
package: 'prepay_id=' + prepay_id,
signType: 'MD5',
paySign: paySign,
success: function (res) {
// 支付成功
},
fail: function (res) {
// 支付失败
}
});
}
需要注意的是,在以上代码示例中,CryptoJS 是一个 JavaScript 加密库,用于进行 SHA1 或 MD5 等加密操作,可以在网上搜索并引入相应的 JavaScript 文件使用。微信支付功能需要先在微信商户平台上注册账号并完成商户认证和资质审核,获取 mch_id 和 api_key,并且需要使用自己的服务器作为支付通知地址。
做前端开发的时候都用到了哪些工具?
vscode,git,apipost
智能柜项目后台各个模块中都做了什么功能?
该项目主要为某企业员工提供智慧储物服务,方便企业员工个人物品的存取
管理员通过后台实现智能柜箱门的分配
员工用微信扫描设备上的二维码即可使用
只有一个模块,即为智能柜使用管理模块,里面功能大概有这些:
1.管理员登录后台,可以对智能柜箱进行管理,如添加、删除、编辑柜箱信息。
2.管理员可以分配柜箱给员工使用,分配时需要设置该柜箱的可用时间和权限等信息。
3.当员工扫描柜箱上的二维码,系统可以自动识别员工身份并验证其是否有权限使用该柜箱,如果没有权限,则无法打开柜门。
4.当柜门被打开时,系统会自动记录打开时间,方便管理员进行后期统计与管理。
5.当柜门内的物品被取出或放入时,员工需要在系统中进行相应的操作,如确认领取、确认归还等。
6.当柜箱发生报警时,系统可以自动推送报警信息给管理员。
7.系统需要记录柜箱的使用情况,包括柜门的开关记录、员工的使用记录以及柜箱的维护保养记录等。
8.员工可以通过微信小程序查看自己的柜箱使用情况,如查看柜箱的可用时间、柜门的开关记录、物品的领取记录等
小李的温馨提示:上述业务场景挑选几个好记的记下来即可。
平时如果调试代码通过什么方式?
debugger,或者在浏览器中ctrl+p找到该源代码进行打断点
es6的新特性
说说es6的新增特性
let、const: 声明变量和常量
模板字符串:增强版的字符串,用反引号标识,嵌入变量只需要放在${}中
箭头函数:ES6中函数定义不再使用关键字function(),而是利用了()=>来进行定义
解构赋值:按照类型的不同有不同的方式提取值,
赋值 Symbol:新增的基本数据类型,特点就是里面的值唯一
Set 和 Map 数据结构
展开运算符(…): 可以将数组或对象里面的值展开, 还可以将 Set 数据结构转换为数组 for…of 循环: 可以遍历数组对象以及 Set 和 Map 数据结构
class 类:通过 extends 实现继承
promise、(async/await): 都是用来解决异步编程的方案 proxy:代理对象,直接监听对象的变化,然后触发相应的逻辑
详情请见小李的另一篇笔记
https://editor.csdn.net/md/?articleId=128697282
这里面详细介绍了es6的新特性
不要懒,好好看一遍哦
把里面的块级作用域,symbol数据类型,箭头函数,const常量,对象的解构赋值这几个说出来就行了,
这些已经很简洁了,后面还有很多,我没记。
说一说知道的HTML标签,越多越详细越好?
什么是标签语义化
合适的地方选择使用合理的标签
HTML 语义化就是让页面的内容结构化,便于对浏览器、搜索引擎解析;在没有样式 CCS 情况下也以一种文档格式显示,并且是容易阅读的。
有利于 SEO。 搜索引擎优化 对搜索引擎的排名状况 关键字搜索后的,显示排名
后边还能再问?你如何做到搜索引擎优化,还有其它方法吗
标题标签 h1~h6
<h1>一级标题</h1>
<h2>二级标题</h2>
<h3>三级标题</h3>
<h4>四级标题</h4>
<h5>五级标题</h5>
<h6>六级标题</h6>
标题标签的默认样式是自动加粗的;
字体大小一级标题最大,六级最小;标题与标题之间有较大的间距 独占一行。
标题标签代表着一个标题,一级标题的语义最重,六级标题的语义最轻。
标题标签是块元素。
标题标签的作用是帮助推广部门进行推广优化的,其重要性仅次于title标签。
一般而言一个页面只有一个h1标签。
段落标签 p
<p>段落标签</p>
段落标签的默认样式是行与行之间有较大间距并独占一行。它代表着一个自然段。
段落标签也是块元素。
hgroup标签
<hgroup>
<h1>登高</h1>
<h2>杜甫</h2>
</hgroup>
hgroup标签主要作用是用来为标题分组,可以将一组相关的标题放到hgroup里面。
强调标签 em strong
你们真<em>帅</em>
你们真<strong>帅</strong>
em和strong标签都表示强调,但是它们还是有一定的差别的
第一em标签的样式是斜体,而strong标签的样式是加粗
第二em标签是强调语义的,而strong标签是强调内容的
em标签和strong标签都是行内元素。
引用标签 q blockquote
老子曰
<blockquote>孔子说的不对</blockquote>
孔子曰
<q>老子才不对</q><br>
q标签和blockquote标签都是引用,不同的是q标签是短引,用而blockquote标签是长引用会换行的。
换行标签 br
点点关注<br>
谢谢你们<br>
萨瓦迪卡<br>
外比八不<br>
br标签的作用是,强制换行,它是一个自结束标签。
hr标签
<hr>
hr标签就是给页面加一个分割线。
del标签
原价 <del>19999</del>
现价 999
这个del标签就是删除标签,就很常见了,什么不要998,不要997现价只有99!等等的广告,还有淘宝上啊、京东上啊,都有这个标签的存在。
center标签
<center> <hgroup>
<h1>登高</h1>
<h2>杜甫</h2>
</hgroup></center>
center标签的作用就是剧中,把文字啊图片啊啥的全部居中到页面中间,这可以让页面更美观。
div标签
<div>
用来布局
</div>
div标签是用来布局的,并没有语义,只是一个区块。
div标签是块元素
span标签
<span>
包裹文字
</span>
常用的布局标签
header 网页的头部
main 网页的主体部分(一般只有一个)
footer 网页的底部
nav 网页的导航
aside 和主题相关的内容
article 文章之类的
section 独立的块区,上面的标签都不合适,就用这个
div 块元素
常用的图片标签
一般来说我们都是使用img标签来引入图片,img标签有四个属性
1.src属性 引入图片路径 通过./或者…/开头
./ 若引用的图片在同一个目录下
../ 若引用图片不在同一个目录(../到上一级目录,可叠加../../)
2.alt属性 对图片的描述,对图片引用不成功的时候显示文字
也会帮助浏览器做一些收录功能
-
width属性 设置图片的宽度
属性值里直接写数值或者带单位
4.height属性 设置图片的高度
属性值里直接写数值或者带单位
注意:一般情况 width和height只设置一个,另一个让浏览器按比例缩放。
块级元素和行级元素有什么区别?
块元素(block element) 常用来布局
特点:
1.块元素会独占一行,从上往下依次排列
2.块元素的宽度是父元素的100%(body是父元素,页面边小随之变小)
3.块元素的高度默认是被内容撑开的
常用块元素:div h1-h6 p header footer nav......
行内元素(inline element)
特点
1.不会独占一行,它是自左向右排列,一行排满再换行
2.行内元素的宽和高,默认是被内容撑开的
常用行内元素:span em strong a i ......
行内块元素
特点
1.兼具块元素和行内元素特点
2.不会独占一行,可自定义宽高
注意:
1.块元素里什么都能放,可以是块元素,行内元素,行内块元素
2.行内元素里一般只放行内元素,如:文字,不能放块元素
3.特殊的块元素p标签它里面一般只放文字或者图片,不能放块元素
4.特殊的行内元素a标签,它里面什么都能放,
可以块元素,行内元素,行内块元素,除了a标签它自己不能放进去。
绝对定位和相对定位有什么区别?
相对定位
每一个元素都可以看作一个盒子,文档流就是由这些盒子堆砌而成,而每个盒子都在这个文档流中占据了一个位置,如果我们把这个盒子设置成相对定位,那么就可以拿起这个盒子相对于它原来所占据的位置向别的地方移动,如设置 left:50px 就是相对于盒子原来位置向右移动了 50 个像素,我们例子来说明。
我们把 box-2 设置成相对定位并向左移动 60 像素,向下移动 120 像素。
.box-2{
background-color: #00A5FF;
position: relative;
left: 60px;
top:120px;
}
则变为下面的情况
从上图我们可以发现 box-2 相对于它原来的位置向下且向右移动了,并且原来的位置留下了一片空白,但是其他的元素并没有占据它,说明元素设置相对定位后,可以相对于其在普通流中的位置偏移,原本所占的空间仍保留。
同时我们从图上可以看出,box-2 移动之后覆盖了其他的元素,这说明当元素被设置相对定位后,将激活 z-index 属性,其层叠级别高于原本的文档流。此时如果给 box-5 也设置 position: relative,那么 box-5 又会覆盖 box-2。
绝对定位
绝对定位的参照物是相对于该元素最近的已定位的祖先元素,如果没有一个祖先元素设置定位,那么参照物是 body。
绝对定位与相对定位的一大不同之处就是,当我们把一个元素设置成绝对定位,那么这个元素将会脱离文档流,漂浮在文档流上方,并且后面的元素将会填充它原来的位置。
绝对定位元素根据它的参照物移动自己的位置,而参照物则需要根据它祖先元素的定位设置来确定。我们就用实例说明绝对定位的特点和需要注意的地方。
例如
祖先元素都没有设置定位,元素相对于 body 转移位置。
给 box-2 设置成 position: absolute;
.box-2{
background-color: #00A5FF;
position: absolute;
}
则出现下面的结果
我们可以看到最后一个 box 存在的位置空了出来,这是因为 box-2 脱离文档流漂浮到文档上方,并且后面的元素填补了上去,说明元素设置绝对定位后脱离文档流,后面的元素将填补它的位置。
接着你可能就会发现 box-3 失踪了,其实它没有失踪,它是在 box-2 下面,就像相对定位一样,当元素被设置绝对定位后,将激活 z-index 属性,其层叠级别高于原本的文档流。
你可能会问了,不是说祖先元素都没有定位时,元素会相对于 body 来改变自己的位置吗,为什么它还是飘在原来的位置,而没有飘到 body 顶头呢,那么请看,我把 left 和 top 属性加上会出现什么样的结果。
如果加上left和top属性
.box-2{
background-color: #00A5FF;
position: absolute;
left: 0;
top:0;
}
现在可以看到它与 body 顶头了,因为光设置一个元素的相对定位它只会漂浮到原来位置的上空,并不会漂浮到参照物的文档流最前方,而只有设置了 left、top、right、bottom 这些参数的时候才能激活它相对于参照物移动的效果。
祖先元素 grandpa 设置定位,元素相对于 grandpa 转移位置
.grandpa{
background-color: #55a532;
height: 500px;
width: 600px;
margin: 40px;
position: relative;
}
.box-2{
background-color: #00A5FF;
position: absolute;
left: 20px;
top:20px;
}
当祖先元素不止一个设置了定位的时候,选择最近的一个作为参照物。
介绍一下常用的css的选择器?
元素选择器
语法 : 标签名{}
作用 : 选中对应标签中的内容
.p{}
.div{}
.span{}
.ol{}
.ul{}
类选择器(class选择器)
语法 : .class属性值{}
作用 : 选中对应class属性值的元素
<p class="A">段落1</p>
<p class="B">段落1</p>
<p class="C">段落1</p>
.A{} , .B{} , .C{}
注意:class里面的属性值不能以数字开头,如果以符号开头,只能是’_‘或者’-'这两个符号,其他的符号不可以,一个class里面可以有多个属性值
id选择器
语法 : #id属性值{}
作用 : 选中对应id属性值的元素
<p id="A">段落1</p>
<p id="B">段落1</p>
<p id="C">段落1</p>
#A{} , #B{} , #C{} ......
注意 : id的属性值只能给1个,可以重复利用,不能以数字开头
通配符选择器
语法 : *{}
作用 : 让页面中所有的标签执行该样式,通常用来清除间距
*{
margin: 0; //外间距
padding: 0; //内间距
}
群组选择器
语法 : 选择器1,选择器2,选择器3…{}
作用 : 同时选中对应选择器的元素
<style>
/* 用群组的目的是为了简化代码量 */
div,p,h3,.li2{
font-size: 30px;
}
div,.li2,.text3{
color: red;
}
p{
color: blue;
}
h3{
color: pink;
}
</style>
<div>盒子1</div>
<p>段落1</p>
<p>段落2</p>
<h3>文本标题3</h3>
<h3 class="text3">文本标题3</h3>
<ol>
<li>有序列表</li>
<li class="li2">有序列表</li>
<li>有序列表</li>
</ol>
后代选择器
后代选择器也叫包含选择器,祖先元素直接或间接的包含后代元素
<style>
/* 后代选择器(包含选择器),选择到的是box下面的所有后代p */
.box p{
width: 200px;
height: 200px;
background-color: yellow;
}
</style>
<div class="box">
<p>0000</p>
<div>
<p>11111</p>
<p>22222</p>
</div>
<div class="box2">
<p>333</p>
</div>
<p>444</p>
</div>
<style>
/* 选择到的是box的后代div的后代p */
.box div p {
width: 200px;
height: 200px;
background-color: yellow;
}
</style>
<div class="box">
<p>0000</p>
<div>
<p>11111</p>
<p>22222</p>
</div>
<div class="box2">
<p>333</p>
</div>
<p>444</p>
</div>
子代选择器
父元素直接包含子元素,子元素直接被父元素包含
<style>
/*子选择器选中的是.box下所有的儿子p
.box>p{
width: 200px;
height: 200px;
background-color: yellow;
}
</style>
<div class="box">
<p>0000</p>
<div>
<p>11111</p>
<p>22222</p>
</div>
<div class="box2">
<p>333</p>
</div>
<p>444</p>
</div>
<style>
/*子选择器选中的是.box下所有儿子div中的儿子p
.box>div>p{
width: 200px;
height: 200px;
background-color: yellow;
}
</style>
<div class="box">
<p>0000</p>
<div>
<p>11111</p>
<p>22222</p>
</div>
<div class="box2">
<p>333</p>
</div>
<p>444</p>
</div>
相邻兄弟选择器
<p>000</p>
<div class="box">盒子1</div>
<p>111</p>
<p>222</p>
<p>333</p>
<div>
<p>44444</p>
</div>
<p>5555</p>
以上面的代码为例,除了内容为’44444’的的p标签外,其余的所有元素均为兄弟元素,而相邻兄弟元素就是紧挨着的两个标签
给上述代码加上内部修饰样式:
<style>
/* 相邻兄弟,会选择到box后面紧挨着的p,那么就是内容为111的p标签 */
.box+p{
width: 200px;
height: 200px;
background-color: yellow;
}
</style>
通用兄弟选择器
<p>000</p>
<div class="box">盒子1</div>
<p>111</p>
<p>222</p>
<p>333</p>
<div>
<p>44444</p>
</div>
<p>5555</p>
同样以上面的代码为例,添加一段内部修饰样式:
<style>
/*通用兄弟选择器,会选择到.box后面所有的兄弟p,
那么就是除了内容为'44444'以外的所有p*/
.box~p{
width: 200px;
height: 200px;
background-color: yellow;
}
</style>
以上面的代码为例,现在有一个需求,想要内容为’5555’的标签自己变换样式,其余的都不变,我们先来分析一下,这个标签很明显,单独选择相邻兄弟元素或者通用兄弟元素都是无法实现只改变p5这个标签,先看看p5标签在.box后面,而.box后面只有一个div标签,刚好p5就是这个div的兄弟元素,代码如下:
<style>
.box~div+p{
width: 200px;
height: 200px;
background-color: yellow;
}
</style>
属性选择器
属性选择器一共有7种写法
1.某某[属性]
2.某某[属性=属性值]
3.某某[属性^=属性值]
4.某某[属性$=属性值]
5.某某[属性*=属性值]
6.某某[属性~=属性值]
7.某某[属性|=属性值]
<style>
.demo {
width: 300px;
border: 1px solid #ccc;
padding: 10px;
overflow: hidden;
margin: 20px auto;
}
.demo a {
float: left;
display: block;
height: 50px;
width: 50px;
border-radius: 10px;
text-align: center;
background: #aac;
color: blue;
font: bold 20px/50px Arial;
margin-right: 5px;
text-decoration: none;
margin: 5px;
}
</style>
<div class="demo">
<a href="http://www.baidu.com" target="_blank" class=" links item first" id="first" title="link">1</a>
<a href="" class="links active item" title="test website" target="_blank" lang="zh">2</a>
<a href="sites/file/test.html" class="links item" title="link-1 aa" lang="zh-cn">3</a>
<a href="sites/file/test.png" class="links item" target="_balnk" lang="zh-tw">4</a>
<a href="sites/file/image.jpg" class="links item" title="link-23 aa">5</a>
<a href="mailto:baidu@hotmail" class="links item" title="website link" lang="zh">6</a>
<a href="/a.pdf" class="links item" title="open the website" lang="cn">7</a>
<a href="/abc.pdf" class="linksitem" title="close the website" lang="en-zh">8</a>
<a href="abcdef.doc" class="links item" title="http://www.sina.com">9</a>
<a href="abd.doc" class="linksitem last" id="last">10</a>
</div>
以上代码的默认样式是这样的:
现在在style标签内写入1~7个方法的修饰样式:
<style>
/* 属性选择器的权重是0010 */
/* 写法1 某某[属性] 选择到a标签且有title属性的变*/
/* a[title]{
background: yellow;
} */
/* a[lang][target]{
background: yellow;
} */
/*重点: 写法2: 某某[属性=属性值] 选择到有某某标签有指定属性且属性值必须一摸一样的也有的多一个空格都不行 */
/* a[lang="zh"]{
background: yellow;
} */
/* a[title="this is a link"]{
background: yellow;
} */
/* class名字是item的,且有属性lang且属性值必须一模一样是zh-cn的 */
/* .item[lang="zh-cn"]{
background: yellow;
} */
/* id是last且有title属性且有class属性,属性值只能是links的变 */
/* #last[title][class="links"]{
background: yellow;
} */
/* 写法3: 某某[属性^=属性值] */
/* a标签有class属性且属性值是li开头的 */
/* a[class^=" li"]{
background-color: yellow;
} */
/* a[title^="this"][lang]{
background-color: yellow;
} */
/* 写法4 某某[属性$=属性值] */
/* a标签有class属性且属性值结尾是t的变 */
/* a[class$="t"]{
background-color: yellow;
} */
/* a[href$=".pdf"]{
background-color: yellow;
}
a[href$=".doc"]{
background-color: red;
}
a[href$=".png"]{
background-color: green;
} */
/* 写法5 某某[属性*=属性值] */
/* 选择到a标签且有href属性且只要有字母b就可以 */
/* a[href*="b"]{
background-color: green;
} */
/* 写法6 某某[属性~=属性值] */
/* 选择到的是a标签且有class属性,且属性值有完整的itme词的变 */
/* a[class~="item"]{
background-color: green;
} */
/* 写法7 某某[属性|=属性值] */
/* 这个是选择到有a标签,且有属性title,且属性值只有1个是link的或者属性值有多个但是得是link-开头的变 */
a[title|="link"]{
background-color: green;
}
</style>
现在默认展示的是第七个方法(需要看其他6种方法的同学自行打开其余6种方法的注释),现在选择到的是有a标签,且有属性title,且属性值只有1个是link的或者属性值有多个但是得是link-开头的变,那么就是第一,第三,和第五个,打开页面看看
伪类选择器
1.常用的伪类选择器
:first-child 第一个子元素
:last-child 最后一个子元素
:nth-child() 选中第n个元素
关于:nth-child()的特殊值(括号内的内容可以填写以下几种)
n 第n个 n的范围0到正无穷(全选)
even或2n 选中偶数位的元素
odd或2n+1 选中奇数位得到元素
以child结尾的是在所有元素中选择
:first-of-type 第一个子元素
:last-of-type 最后一个子元素
:nth-of-type() 选中第n个元素
以type结尾的是在相同元素中选择
<style>
/* box下面的第1个子元素变,也就是p1变 */
.box :first-child{
border: 2px solid blue;
}
/* box下面的第1个子元素是li的时候变*/
.box li:first-child{
border: 2px solid blue;
}
.box p:first-child{
border: 2px solid blue;
}
/* box下面的最后1个子元素变,也就是p6变 */
.box :last-child{
border: 2px solid blue;
}
.box p:last-child{
border: 2px solid blue;
}
/* box下面的第3个子元素变 */
.box :nth-child(3){
border: 2px solid blue;
}
.box li:nth-child(3){
border: 2px solid blue;
}
/* box下面的第7个子元素是p的变 */
.box p:nth-child(7){
border: 2px solid blue;
}
.box p:nth-child(9){
border: 2px solid blue;
}
/* n是从0开始的数列 把n=0开始往n+3里面计算就可 */
/* n=0 n+3=3 */
/* n=1 n+3=4 */
/* n=2 n+3=5... 结果就是第3,4,5,6,7,8,9...变*/
.box :nth-child(n+3){
border: 2px solid blue;
}
/* box下面的第3,4,5,6,7,8,9...是li的时候变 */
.box li:nth-child(n+3){
border: 2px solid blue;
}
/* 表示的意思是box里面的第3,2,1个变 */
.box :nth-child(-n+3){
border: 2px solid blue;
}
/* 表示的意思是box里面的第3,2,1个是p变 */
.box p:nth-child(-n+3){
border: 2px solid blue;
}
/* 表示的意思是box里面的第2,4,6,8,10,12.... 偶数的 */
.box :nth-child(2n){
border: 2px solid blue;
}
.box :first-child{
border: 2px solid red;
}
/* 表示的意思是box里面的第2,4,6,8,10,12....是li的变 偶数的 */
.box li:nth-child(2n){
border: 2px solid blue;
}
/* 2n和even都是偶数的意思 */
.box li:nth-child(even){
border: 2px solid blue;
}
/* 表示的意思是box里面的第1,3,5,7,9...个变也就是奇数变 */
.box :nth-child(2n+1){
border: 2px solid blue;
}
.box :nth-child(odd){
border: 2px solid blue;
}
/* 5 7 9 .... */
.box :nth-child(2n+5){
border: 2px solid blue;
}
.box :nth-last-child(2n){
border: 2px solid blue;
}
.box :only-child{
border: 2px solid blue;
}
</style>
<ul class="box">
<p>1111</p>
<p>222</p>
<li>无序列表的li1</li>
<p>33333</p>
<li>无序列表的li2</li>
<li>无序列表的li3</li>
<p>44444</p>
<li>无序列表的li4</li>
<p>555</p>
<li>无序列表的li5</li>
<p>666</p>
</ul>
<style>
/* box下面的第1个子元素变,从结构看第1个是p,所以p1变了 */
.box :first-child{
border: 2px solid blue;
}
/* box下面的同类型的第1个变,从目前的结构上看ul下面有2个类型,1个是li和1个是p所以li类型和p类型的第1个都变了 */
.box :first-of-type{
border: 2px solid blue;
}
/* -child和-type的区别 child只看某个父元素下面的子元素 -type看的某父元素下面的同类型的子元素 child就是问班级有多少人 type就是问班级有多少女生和多少男生 */
.box :last-of-type{
border: 2px solid blue;
}
.box p:last-of-type{
border: 2px solid blue;
}
/* box 里面的p的第2个 */
.box p:nth-of-type(6){
border: 2px solid blue;
}
/* 选择box中li里面的第偶数个 */
.box li:nth-of-type(2n){
border: 2px solid blue;
}
.box li:nth-of-type(2n+1){
border: 2px solid blue;
}
.box li:nth-last-of-type(2){
border: 2px solid blue;
}
/* box里面的只有1个子元素是li的时候变 */
.box li:only-child{
border: 2px solid blue;
}
/* box里面的li只有1个的时候变 */
.box li:only-of-type{
border: 2px solid blue;
}
.box :nth-last-child(2){
border: 3px solid blue;
}
.box :nth-last-of-type(2){
border: 3px solid blue;
}
</style>
<ul class="box">
<p>1111</p>
<p>222</p>
<li>无序列表的li1</li>
<p>33333</p>
<li>无序列表的li2</li>
<li>无序列表的li3</li>
<p>44444</p>
<li>无序列表的li4</li>
<p>555</p>
<li>无序列表的li5</li>
<p>666</p>
</ul>
否定伪类
:not() 将符号条件的元素去除
元素的伪类
:link 表示未访问过的a标签
:visited 表示访问过的a标签
以上两个伪类是超链接所独有的
由于隐私的问题,所以visited这个伪类只能修改链接的颜色
以下两个伪类是所有标签都可以使用
:hover 鼠标移入后元素的状态
:active 鼠标点击后,元素的状态
伪元素选择器
同伪类一样,伪元素也是不存在的元素,表示元素的特殊状态
常见的几个伪元素:
::first-letter 表示第一个字母
::first-line 表示第一行
::selection 表示选中的元素
::before 元素开始的位置前
::after 元素结束的位置后
befor和after必须配合contend一起使用(before,after所写的内容无法选中且永远在最前和最后)
css的盒子模型了解吗?
说一说你对盒模型的理解
而目前市面上存在 2 中盒模型:标准盒模型 和IE 盒子模型,它俩对计算宽度和高度的不同。
先说标准盒模型,也就是 W3C 规定的盒子模型。
盒子总宽度 = width + padding + border + margin。
盒子总高度 = height + padding + border +margin。
在标准模式下:
也就是(划重点啦!!!)我们设置的 width/height 只是内容 content(上图橙色的部分)的宽/高度,不包含 padding 和 border 值。
在使用CSS进行网页布局时,我们一定离不开的一个东西————盒子模型。盒子模型,顾名思义,盒子就是用来装东西的,它装的东西就是HTML元素的内容。或者说,每一个可见的 HTML 元素都是一个盒子,下面所说的盒子都等同于 HTML 元素。这里盒子与 中的盒子又有点不同,这里的盒子是二维的。
一个盒子由外到内可以分成四个部分:
margin(外边距)、border(边框)、padding(内边距)、content(内容)
会发现margin、border、padding是CSS属性,因此可以通过这三个属性来控制盒子的这三个部分。
而content则是HTML元素的内容。
比如说现在让你去做一个百度的首页,你会怎么设计它的布局?代码会怎么写?
完整的网页的布局顺序
1.先对网页整体的区域进行划分,划分为多个div区域。
百度首页由头部的一个文字导航,中间的一个按钮和一个输入框以及下边的文字简介和导航组成(可以先大致设置3个div,即上 ,中 ,下三部分)。
文字导航部分(上)
按钮和输入框部分(中)
下面的文字简介和导航组成(下)
2.对每一块区域进行上色(宽,高,背景颜色),依次调整间距,做出实际的布局效果。
3.单独去布局每一块区域的内容(按照1,2,3步骤)。
4.Css属性
a)盒模型相关的属性:margin,padding,border,width,height。
b)文本相关的属性:color,font-size,line-height,font-family,text-dercoration,letter-sacing等
c)处理新问题:display: inline-block; vertical-align:top;
间隙问题的处理?
1.Html元素自带的间隙问题。
解决方案:添加通配选择器,清除元素自带的盒模型结构。
*{ margin:0; pading:0;}
2.行属性标签以及行内块属性自带间隙问题。
解决方式1:将分行写的代码放置在同一行写。
解决方式2:
a. 将所有的行元素放置在一个div中。
b. 给div设置字体大小为0的属性。
c. 将行元素字体设置为想要的字体大小。
解决方式3:浮动。
3.图片对齐方式的问题。
解决方案:给图片添加vertical-align属性,默认值是baseline基线对齐,只需要给上其他值即可。Vertical-align: top | middle | bottom;
实现代码
(注意:网页结构和样式是分开来写的即外联式):
a.百度网页大体结构(主旨部分):
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<!--外部引入的方式-->
<link rel="stylesheet" type="text/css" href="css/baidu.css"/>
</head>
<body>
<!--
1.先写网页的结构,每一块区域单独的色块。
2.调整色块与色块之间的间距。
-->
<!--上-->
<div class="top">
<a href="https://voice.baidu.com/act/newpneumonia/newpneumonia/?from=osari_pc_1">抗击肺炎</a>
<a href="http://news.baidu.com/">新闻</a>
<a href="https://www.hao123.com/">hao123</a>
<a href="https://map.baidu.com/@12527476.18,3871381.71,12z">地图</a>
<a href="http://v.baidu.com/">视频</a>
<a href="https://tieba.baidu.com/index.html">贴吧</a>
<a href="http://xueshu.baidu.com/">学术</a>
<a href="#" class="top_a">登录</a>
<a href="#" class="top_a">设置</a>
<a href="#" id="more">更多产品</a>
</div>
<!--中-->
<div class="middle">
<a href="https://www.baidu.com/s?wd=%e6%8a%97%e7%96%ab%e4%b8%93%e5%ae%b6%e7%bb%84&sa=ire_dl_gh_logo&rsv_dl=igh_logo_pcs"><img src="img/QQ图片20200216111859.png"/></a>
<!--输入框和按钮-->
<div class="input">
<!--输入框--> <!--按钮-->
<input type="text" class="input_text"/><input type="button" value="百度一下"/ class="input_button">
</div>
</div>
<!--下-->
<div class="bottom">
<img src="img/code.png"/>
<p class="download">下载百度APP</p>
<p class="look">有事搜一搜 没事看一看</p>
<div class="about">
<a href="https://www.baidu.com/cache/sethelp/help.html">把百度设为首页</a>
<a href="http://home.baidu.com/">关于百度</a>
<a href="http://ir.baidu.com/">About Baidu</a>
<a href="http://e.baidu.com/ebaidu/home?refer=888">百度推广</a>
<span>(京)-经营性-2017-0020</span>
</div>
<div class="copyright">
<span>©2020 Baidu</span>
<a href="https://www.baidu.com/duty/">使用百度前必读</a>
<a href="http://jianyi.baidu.com/">意见反馈 </a>
<span>京ICP证030173号</span>
<img src="img/1.png"/>
<a href="http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=11000002000001" id="record">京公网安备110000020</a>
<img src="img/2.png"/>
</div>
</div>
</body>
</html>
b.css样式(实现网页的布局,让网页变得更加美观,实现所期望的效果):
/*通配选择器清除间隙*/
*{
margin: 0;
padding: 0;
}
.top{
/*内容右对齐*/
text-align: right;
/*上填充*/
padding-top: 19px;
/*右填充*/
padding-right: 11px;
}
/*子代选择器*/
.top>a{
/*文字相关的属性*/
color: #333333;
/*文字字体*/
font-weight: 700;
font-size: 13px;
line-height: 24px;
/*文字字体*/
font-family: arial;
/*左间距*/
margin-left: 20px;
}
.top>.top_a{
/*调整文字粗细*/
font-weight: 400;
}
#more{
/*宽高*/
width: 60px;
height: 24px;
/*
a标签是一个行属性标签,行属性标签是无法改变宽高的,宽高由内容撑开
如果想让a标签能够设置宽高,比如给a标签添加一个display: inline-block;
*/
background-color: #3388ff;
/*去掉下划线*/
text-decoration: none;
color: white;
font-weight: 400;
/*水平居中*/
text-align: center;
}
.middle{
/*上间距*/
margin-top: 138px;
/*内容居中*/
text-align: center;
}
.middle>img{
width: 270px;
}
.input{
/*上间距*/
margin-top: 25px;
}
/*输入框*/
.input_text{
width: 532px;
height: 34px;
border: 1px solid #b6b6b6;
/*去掉右边框 - 将右边框宽度设置为0*/
/*border-right-width: 0;*/
border-right: none;
/*左填充*/
padding-left: 7px;
}
/*按钮*/
.input_button{
width: 100px;
height: 36px;
background-color: #3385ff;
color: white;
border: 1px solid #3385ff;
/*垂直对齐方式*/
vertical-align: top;
}
.bottom{
/*上间距*/
margin-top: 256px;
text-align: center;
}
.download{
/*文本相关*/
color: #333333;
font-size: 16px;
line-height: 32px;
/*字母间距*/
letter-spacing: 3px;
/*字体*/
font-family: arial;
}
.look{
color: #999;
font-size: 14px;
font-weight: 300;
line-height: 14px;
}
.about{
/*文本相关的属性*/
color: #999;
font-size: 12px;
line-height: 22px;
font-family: arial;
/*上间距*/
margin-top: 25px;
}
/* a元素对文字有自己的颜色设置,所以如果想修改a元素中文字的颜色,就必须作用到a标签上的颜色*/
.about>a{
color: #999;
/*右间距*/
margin-right: 25px;
}
.copyright{
color: #999;
font-size: 12px;
line-height: 24px;
font-family: arial;
}
.copyright>a{
color: #999;
}
.copyright>img{
/*修改图片的垂直对齐方式 -- 垂直居中对齐*/
vertical-align: middle;
}
#record{
/*左间距*/
margin-left: 15px;
}
.bottom>img{
border: 1px solid #f3f3f3;
padding: 5px;
}
之前做的页面是否有考虑过对不同浏览器的兼容?
1.不同浏览器的标签默认外边距margin和内边距padding不同
解决方案:
使用CSS通配符*,设置内外补丁为0,*{ margin: 0; padding: 0;}
2.图片默认有间距
几个img标签放在一起的时候,有些浏览器会有默认的间距,通配符清除间距也不起作用。
解决方案:
使用float属性为img布局
3.子容器宽度大于父容器宽度时,内容超出
问题:子DIV的宽度和父DIV的宽度都已经定义,在IE6中如果其子DIV的宽度大于父DIV的宽度,父DIV的宽度将会被扩展,在其他浏览器中父DIV的宽度将不会扩展,子DIV将超出父DIV
解决:设置overflow:hidden,子DIV将不会超出父DIV。
4.上下margin的重叠问题
描述:给上边元素设置了margin-bottom,给下边元素设置了margin-top,浏览器只会识别较大值;
解决方案:margin-top和margin-bottom中选择一个,只设置其中一个值;
5.IE6 双倍边距的问题
设置 ie6 中设置浮动,同时又设置 margin,会出现双倍边距的问题
解决方案:在float标签样式控制中加入display:inline;
请举例说明如何使用 CSS 实现响应式布局?
实现响应式布局通常会使用 CSS 中的媒体查询(Media Query)。通过媒体查询,可以根据设备的特性,如屏幕宽度、高度、屏幕方向等进行样式的选择性修改。以下是使用CSS实现响应式布局的一个简单例子:
/* 默认样式 */
.container {
width: 960px;
margin: 0 auto;
}
/* 媒体查询:在设备宽度小于 768px 时应用此样式 */
@media (max-width: 768px) {
.container {
width: 100%;
padding: 20px;
box-sizing: border-box;
}
}
代码中的意思是,当设备宽度小于 768px 时,.container 元素的宽度为100%,并设置了一些样式。
cookie、sessionStorage、localStorage的区别?
cookie生命期是只在设置过期时间之前一直有效,即使窗口或浏览器关闭。
sessionStorage仅在当前会话下有效,关闭页面或浏览器后被清除数据。因此sessionStorage仅仅是会话级别的存储。
而localStorage用于持久化的本地存储,除非主动删除数据,否则数据是永远不会过期的。
之前做的页面是否考虑过兼容移动端?
响应式设计:使用流行的响应式设计框架(如Bootstrap、Foundation等)或自定义响应式设计可以使网站在不同屏幕尺寸下显示正常,并保持良好的用户体验。
使用流体布局:使用百分比、vw、vh等单位进行布局可以使页面在不同尺寸的屏幕上自适应,并且不会破坏页面布局。
图片优化:对所有的图片进行优化(如压缩、裁剪等),并使用WebP格式可以减少页面加载时间。
使用媒体查询:使用CSS3媒体查询可以根据屏幕大小、分辨率等条件设置不同的样式。
测试:使用不同的移动设备进行测试,确保页面在移动设备上的兼容性,并及时修复问题。
对于前端性能优化,你有哪些实践经验?
1.使用 Webpack 等打包工具对 JavaScript、CSS 和图片等资源进行合并和压缩,减少网络请求次数和资源大小。
2.精简 CSS 和 JavaScript 代码,删除无用的代码和注释,并尽量避免在主线程上执行耗时操作。
3.从服务端返回静态资源时,使用缓存控制机制,以便客户端能够缓存这些资源,减少后续的请求和传输时间。
4.页面加载时,使用懒加载技术,只加载当前可见区域内的图片和内容。
5.避免使用过多的第三方库和插件,以及防止出现代码冗余和错综复杂的依赖关系。
6.优化图片大小和格式,使用适当的图片压缩工具和格式。
7.借助 Chrome 浏览器自带的性能分析工具,如 Lighthouse 和 Performance,找出性能瓶颈并进行优化。
8.使用 CDN 加速静态资源的传输,将资源部署到距离用户更近的服务器上,减少传输时间。
是否有考虑过页面性能提升的问题?
压缩文件:压缩HTML、CSS、JavaScript等文件,可以减小文件大小,缩短页面加载时间。
删减页面元素:如果有大量无用的图片、视频或其他多媒体元素,可以适当删除,减少网络传输数据量。
缓存机制:使用浏览器缓存机制,减少相同资源的重复请求,可以提高页面访问速度。
图片优化:对图片进行压缩、裁剪、延迟加载等优化,减小图片大小,进一步提高页面访问速度。
git常用命令以及冲突解决?
git add # 将工作区的修改提交到暂存区
git commit # 将暂存区的修改提交到当前分支
git push # 将本地代码更新到远程分支上
git branch # 查看当前分支
git checkout # 切换分支
git status # 查看当前仓库的状态
git merge # 合并分支
git pull # 从远程更新代码
git log # 查看提交历史
git reset # 回退到某一个版本
git stash # 保存某次修改
git reflog # 查看历史命令
git diff # 查看修改
git revert # 回退某个修改
什么是跨域?如何解决?
跨域问题是由浏览器的同源策略(Same-Origin Policy)引起的,为了保护用户隐私和安全。简单来说,如果请求的协议、域名、端口号有任何一个不同,就会被认为跨域了。
JavaScript解决跨域问题主要有以下几种方法:
JSONP(JSON with Padding)
JSONP是一种利用script标签跨域获取数据的方法。它的原理是在页面中添加一个script标签,标签的src属性指向跨域获取数据的URL,服务器返回的数据包裹在一个callback函数中,通过该函数处理数据。
CORS(Cross-Origin Resource Sharing)
CORS是一种官方支持的跨域解决方案。CORS通过在服务器设置响应头来告诉浏览器允许跨域请求。客户端发送ajax请求时会自动携带Origin头部信息,服务器收到请求后判断是否允许该域名的请求进行跨域访问,如果允许则在响应头中添加Access-Control-Allow-Origin等相关信息。
你有了解作用域吗?什么是作用域链?
作用域就是一个变量可以生效的范围。
ES5 中作用域有:全局作用域、函数作用域。没有块作用域的概念。
ES6 中新增了块级作用域。块作用域由 { } 包括,if语句和 for语句里面的{ }也属于块作用域。
每个函数都有一个作用域链,查找变量或者函数时,需要从局部作用域到全局作用域依次查找,这些作用域的集合称作作用域链
var、let、const的区别?
var声明的变量可进行变量提升,let和const不会,var可以重复声明,可以跨块访问, 不能跨函数访问。
let声明的变量只在局部起作用,可以防止变量污染,不可在声明。
const用来定义常量,使用时必须初始化(赋值),只能在块作用域里访问,而且不能修改。修改对象的属性值不会改变对象的指针,所以是被允许的。
前端网页有几层构成?
结构层:由HTML之类的标记语言负责创建,即是标签。
表示层:由CSS去负责如何展示。
行为层:由JS去负责网页动作行为反应。
原型和原型链是什么?
原型
①所有引用类型都有一个__proto__(隐式原型)属性,属性值是一个普通的对象
②所有函数都有一个prototype(原型)属性,属性值是一个普通的对象
③所有引用类型的__proto__属性指向它构造函数的prototype
var a = [1,2,3];
a.__proto__ === Array.prototype; // true
原型链
当访问一个对象的某个属性时,会先在这个对象本身属性上查找,如果没有找到,则会去它的__proto__隐式原型上查找,即它的构造函数的prototype,如果还没有找到就会再在构造函数的prototype的__proto__中查找,这样一层一层向上查找就会形成一个链式结构,我们称为原型链。
前端和后端通信是用的哪种方式?
axios的方式
用axios发起restful风格的接口
get请求和post请求有什么区别?
get参数通过URL传递,post放在Request body中
get请求传参是有长度限制的,而post没有限制
get在浏览器回退不会再次请求,post会再次提交请求
get参数暴露在地址栏中不够安全,post放在报文内部更安全
get一般用于查询信息,post一般用于提交某种信息进行某些修改操作
get请求会被浏览器主动缓存,post不会,要手动设置
get请求参数会被完整保留在浏览器历史记录里,post中的参数不会
get产生一个TCP数据包;post产生两个TCP数据包
get请求只能进行url编码,而post支持多种编码方式
get和post的选择:
1.私密性的信息请求使用post(如注册、登陆)。
2.查询信息使用get。
什么是防抖,什么是节流?
防抖:当用户在一段时间内连续频繁的试图执行一个函数的时候,只有最后一次,函数被真正的执行
防抖的实现:
在JS中,防抖是指指触发事件后n秒后才执行函数,如果在 n 秒内又触发了事件,则会重新计算函数执行时间;
function debounce(){
let id;
return function(){
clearTimeout(id);
id = setTimeout(function(){
console.log('button clicked',id)
},1000);
}
}
var fn = debounce();
$("#btn1").on('click',function(e){
fn();
})
节流:当用户在某一个时刻执行了一次函数的时候,在一段时间 t 内,再次执行该函数都没有作用。
function throttle() {
let time = new Date();
return function () {
let time1 = new Date();
if (time1 - time > 2000) {
console.log(time1 - time);
time = time1;
}
}
}
let fn = throttle();
$("#btn1").on('click', function (e) {
fn();
})
请问你能够介绍一下什么是RESTful API,以及如何设计符合RESTful风格的API接口?请结合实际经验谈一下
使用集合路径:使用集合路径可以使API更易于理解和使用,并且使URL更具可读性。例如,假设你有一个名为users的资源集合,那么可以使用/users路径来表示。
使用HTTP状态码:HTTP状态码可以让客户端了解服务端处理请求的结果。例如,当成功读取一个用户时,可以返回HTTP状态码为200 OK
什么是异步编程?请分别介绍回调函数、Promise 和 async/await 三种异步编程方式的特点和使用方法
异步编程是指代码执行时不会阻塞线程,而是在当前线程执行其他任务,等异步操作完成后再回到原来的任务。这种方式能够提高程序的性能和响应速度。在Web开发中,异步编程是非常重要的一部分,因为大量的操作必须要从网络或其他设备获取数据。
以下是回调函数、Promise和async/await三种异步编程方式的特点和使用方法:
回调函数
回调函数是一种最基本和常见的异步编程方式,它是把一个函数作为参数传递给另一个函数,当异步操作完成后,调用这个函数处理异步操作的结果。
特点:
回调函数写法简单,容易理解和实现
可以实现异步操作的串行执行、并行执行等。
使用方法:
function asyncOperation(callback) {
// 异步操作
// ...
// 在异步操作完成后,执行回调函数callback
callback(result);
}
// 调用异步函数
asyncOperation(function(result) {
// 处理异步操作的结果
});
Promise
Promise是ES6引入的一种异步编程方式,它提供了更加优雅的处理异步操作的方式。Promise对象表示一个异步操作的最终状态(成功或失败),并且提供了链式调用和错误处理等功能。
特点:
Promise对象可以很好地解决回调函数嵌套和错误处理等问题
Promise对象支持链式调用,可以实现多个异步操作的串行执行
Promise对错误进行封装,可以通过.catch()方法捕获错误。
使用方法:
function asyncOperation() {
return new Promise(function(resolve, reject) {
// 异步操作
// ...
// 在异步操作完成后,调用resolve()或reject()函数
if (success) {
resolve(result);
} else {
reject(error);
}
});
}
// 调用异步函数
asyncOperation().then(function(result) {
// 处理异步操作的结果
}).catch(function(error) {
// 处理异常情况
});
async/await
async/await是ES7引入的异步编程方式,通过async函数和await关键字来简化Promise代码的编写,从而使异步操作更加直观易懂。async函数是返回一个Promise对象的函数,而await关键字用于等待一个异步操作的结果。
特点:
async/await代码看起来更加简洁和直观,易于理解和维护
async/await能够很好地处理异步操作的结果,并且支持错误处理等功能。
使用方法:
async function asyncOperation() {
try {
// 等待异步操作结果
const result = await someAsyncFunction();
// 处理异步操作的结果
} catch (error) {
// 处理异常情况
}
}
// 调用异步函数
asyncOperation();
以上是回调函数、Promise和async/await三种异步编程方式的特点和使用方法。每一种方式都有其优缺点,具体使用哪种方式取决于具体场景和需求。
常用的HTTP返回码有哪些?
200
这个代表正常返回,使我们最希望获得到的返回码
400
这个和404差不多,不过他是找到了这个路径,只不过传的参数不对导致的
404
这个代表找不到具体的路径,比较常见,一般是前后端联调的时候看错了或者填错了
500
看见这个码就去找后端吧,一般是后台报错了
302
这个码是重定向,证明你发的请求被重新定向到另一个地址了
小李的温馨提示
这几个都要记住,实际上还有很多,但其他的都不常见了。
JS 的数据类型有哪些?
巧记js中的7中数据类型
可以记作 u so nb 你很牛逼
u 是 undefined
so 是 string 和 symbol 和 object
n 是 null 和 number
b 是 boolean
什么是闭包?请给出一个闭包的实际应用场景。
闭包指的是函数嵌套函数,并且子函数能够访问父函数作用域内的变量。当父函数执行完毕后,其内部变量在内存中仍然存在,因此子函数可以继续访问和操作这些变量。
一个闭包的实际应用场景是在JavaScript中进行模块化开发时。在模块化开发中,我们通常使用闭包来封装一些私有变量和方法,以避免污染全局命名空间。例如:
var module = (function() {
// 私有变量和方法
var privateVar = 0;
function privateMethod() {
return privateVar++;
}
// 公共接口
return {
publicMethod: function() {
return privateMethod();
}
};
})();
// 调用模块的公共接口
console.log(module.publicMethod()); // 输出: 0
console.log(module.publicMethod()); // 输出: 1
在上面的例子中,我们使用闭包来创建了一个模块。该模块有一个私有变量privateVar和一个私有方法privateMethod,并且通过返回一个拥有公共接口的对象,使得外部代码只能通过公共接口来访问和调用模块中的方法。这样就能够有效地封装私有变量和方法,避免对全局命名空间的影响。
null 和undefined区别有什么?
undefined是压根就没有这个变量
null是有这个变量,但值为空
js数据类型检测的方式有哪些
(1)typeof
console.log(typeof 2); // number
console.log(typeof true); // boolean
console.log(typeof 'str'); // string
console.log(typeof []); // object
console.log(typeof function(){}); // function
console.log(typeof {}); // object
console.log(typeof undefined); // undefined
console.log(typeof null); // object
其中数组、对象、null都会被判断为object,其他判断都正确。
(2)instanceof
instanceof可以正确判断对象的类型,其内部运行机制是判断在其原型链中能否找到该类型的原型
console.log(2 instanceof Number); // false
console.log(true instanceof Boolean); // false
console.log('str' instanceof String); // false
console.log([] instanceof Array); // true
console.log(function(){} instanceof Function);// true
console.log({} instanceof Object); // true
可以看到,instanceof只能正确判断引用数据类型,而不能判断基本数据类型。
instanceof 运算符可以用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。
请简述一下 JavaScript 中的事件委托机制是什么?
JavaScript 中的事件委托机制是指将事件监听器添加到上层元素(如 document 或其祖先元素)上,而不是直接在每个子元素上添加事件监听器。当发生事件时,事件会冒泡到上层元素,在上层元素上触发事件监听器,然后通过判断事件源来执行对应的处理程序。
这种机制有如下优点:
减少内存占用:使用事件委托可以减少添加事件监听器的数量,从而减少内存占用。如果直接向每个子元素添加事件监听器,会造成内存浪费和性能问题,尤其是在动态添加大量子元素时。
简化代码编写:使用事件委托可以让代码更简洁、易读和易于维护。对于需要监听多个子元素事件的情况,使用事件委托可以避免重复的代码。
动态绑定事件:使用事件委托可以做到动态添加、删除监听器,便于实现动态交互效果。
扩展:能举一个例子说明JS事件委托的优点吗
当我们需要在一个列表中添加或删除某个项目时,如果每个项目都绑定了事件处理程序,会导致内存占用和性能问题。这时可以使用事件委托机制来优化代码。
假设我们有一个ul元素作为列表容器,并且它包含多个li元素表示各个项目。现在我们需要添加删除功能,即点击某个项目可以删除它。
如果直接给每个li元素都绑定删除事件监听器,代码如下:
const items = document.querySelectorAll('li');
for (let i = 0; i < items.length; i++) {
items[i].addEventListener('click', function() {
this.parentNode.removeChild(this);
});
}
但是,如果我们使用事件委托机制,将事件监听器添加到ul元素上,然后通过判断事件源来执行对应的处理程序,代码如下:
const list = document.querySelector('ul');
list.addEventListener('click', function(event) {
if (event.target.tagName === 'LI') {
event.target.parentNode.removeChild(event.target);
}
});
这个例子中,事件委托机制减少了添加事件监听器的数量,避免了内存浪费和性能问题,同时也让代码更加简洁、易读和易于维护。
JS 中对字符串和数组的操作,知道哪些常用的方法?
字符串的方法
charAt() //获取指定位置处字符
charCodeAt() //获取指定位置处字符的ASCII码
// 2 字符串操作方法
concat() //拼接字符串,等效于+,+更常用
slice() //从start位置开始,截取到end位置,end取不到
substring() //从start位置开始,截取到end位置,end取不到
substr() //从start位置开始,截取length个字符
// 3 位置方法
indexOf() //返回指定内容在元字符串中的位置,从前往后找第一个
lastIndexOf() //从后往前找,只找第一个匹配的
// 4 去除空白
trim() // 只能去除字符串前后的空白,字符串之间的空格不能去掉
// 5 大小写转换方法
to(Locale)UpperCase() //转换大写
to(Locale)LowerCase() //转换小写
// 6 其它
search() // 不存在返回-1,search支持正则。
replace() // 替换
split() // 返回数组
fromCharCode()
String.fromCharCode(101, 102, 103); //把ASCII码转换成字符串
数组的方法
push(),向数组的末尾添加一个或多个元素,并返回新的数组长度。原数组改变
pop(),删除并返回数组的最后一个元素,若该数组为空,则返回undefined。原数组改变
unshift(),向数组的开头添加一个或多个元素,并返回新的数组长度。原数组改变
shift(),删除数组的第一项,并返回第一个元素的值。若该数组为空,则返回undefined。原数组改变。
concat(arr1,arr2…),合并两个或多个数组,生成一个新的数组。原数组不变
join(),将数组的每一项用指定字符连接形成一个字符串。默认连接字符为 “,” 逗号
reverse(),将数组倒序。原数组改变。
sort(),对数组元素进行排序。按照字符串UniCode码排序,原数组改变
map(function),原数组的每一项执行函数后,返回一个新的数组。原数组不变
slice(start,end),从start开始,end之前结束,不到end;如果不给end值,从start开始到数组结束。start可以给负值,-1表示数组最后位置,-2表示倒数第二个,以此类推,顾前不顾后。
splice(index,howmany,arr1,arr2…) ,删除元素并添加元素,从index位置开始删除howmany个元素,并将arr1、arr2…数据从index位置依次插入。howmany为0时,则不删除元素。原数组改变。
forEach(function),用于调用数组的每个元素,并将元素传递给回调函数。原数组不变。(注意该方法和map的区别,若直接打印Array.forEach,结果为undefined)
filter(function),过滤数组中,符合条件的元素并返回一个新的数组
every(function),对数组中的每一项进行判断,若都符合则返回true,否则返回false。
Array.some(function),对数组中的每一项进行判断,若都不符合则返回false,否则返回true。
Array.reduce(function),reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。
基本的dom操作有了解吗?
了解过,但是vue项目一般不鼓励直接操作dom元素,所以不经常用
(vue中一般都用)
节点创建型API
createElement
createElement通过传入指定的一个标签名来创建一个元素,如果传入的标签名是一个未知的,则会创建一个自定义的标签。
注意:IE8以下浏览器不支持自定义标签
var div = document.createElement("div");
createTextNode
createTextNode用来创建一个文本节点,用法如下
var textNode = document.createTextNode("一个TextNode");
createTextNode接收一个参数,这个参数就是文本节点中的文本,和createElement一样,创建后的文本节点也只是独立的一个节点,同样需要append Child将其添加到HTML文档树中
cloneNode
cloneNode是用来返回调用方法的节点的一个副本,它接收一个bool参数,用来表示是否复制子元素,使用如下:
var parent = document.getElementById("parentElement");
var parent2 = parent.cloneNode(true);// 传入true
parent2.id = "parent2";
这段代码通过cloneNode复制了一份parent元素,其中cloneNode的参数为true,表示parent的子节点也被复制,如果传入false,则表示只复制了parent节点
这里有几点要注意:
和createElement一样,cloneNode创建的节点只是游离有html文档外的节点,要调用appendChild方法才能添加到文档树中
如果复制的元素有id,则其副本同样会包含该id,由于id具有唯一性,所以在复制节点后必须要修改其id
调用接收的bool参数最好传入,如果不传入该参数,不同浏览器对其默认值的处理可能不同
除此之外,我们还有一个需要注意的点:
如果被复制的节点绑定了事件,则副本也会跟着绑定该事件吗?这里要分情况讨论:
如果是通过addEventListener或者比如onclick进行绑定事件,则副本节点不会绑定该事件
如果是内联方式绑定比如
<div onclick="showParent()"></div>
这样的话,副本节点同样会触发事件
需要注意下面几点:
它们创建的节点只是一个孤立的节点,
要通过appendChild添加到文档中
cloneNode要注意如果被复制的节点是否包含子节点以及事件绑定等问题
页面修改形API
createElement、createTextNode、cloneNode它们只是创建节点,并没有真正修改到页面内容,而是要调用appendChild来将其添加到文档树中。我在这里将这类会修改到页面内容归为一类。
appendChild
就是将指定的节点添加到调用该方法的节点的子元素的末尾。调用方法如下:
parent.appendChild(child);
child节点将会作为parent节点的最后一个子节点
注意:
如果被添加的节点是一个页面中存在的节点,则执行后这个节点将会添加到指定位置,其原本所在的位置将移除该节点,也就是说不会同时存在两个该节点在页面上,相当于把这个节点移动到另一个地方
如果child绑定了事件,被移动时,它依然绑定着该事件
insertBefore
insertBefore用来添加一个节点到一个参照节点之前
parentNode.insertBefore(newNode,refNode);
parentNode表示新节点被添加后的父节点
newNode表示要添加的节点
refNode表示参照节点,新节点会添加到这个节点之前
<div id="parent">
父节点
<div id="child">子元素</div>
</div>
<input type="button" id="insertNode" value="插入节点" />
<script>
var parent = document.getElementById("parent");
var child = document.getElementById("child");
document.getElementById("insertNode").onclick = function(){
var newNode = document.createElement("div");
newNode.textContent = "新节点"
parent.insertBefore(newNode,child);
}
</script>
和appendChild一样,如果插入的节点是页面上的节点,则会移动该节点到指定位置,并且保留其绑定的事件。
关于第二个参数参照节点还有几个注意的地方:
refNode是必传的,如果不传该参数会报错
如果refNode是undefined或null,则insertBefore会将节点添加到子元素的末尾
深拷贝和浅拷贝区别,如何实现
浅拷贝:
只是把对象的属性和属性值拷贝到另一个对象中,新旧对象还是共享同一块内存。方法有:Object.assign()、展开运算符、concat()、slice().
深拷贝:
深拷贝是把一个对象从内存中完整的拷贝出来,又在堆内存中开辟了新区域,用来存储新对象,并且修改新对象不会影响原对象。方法有 JSON.parse(JSON.stringify()).
箭头函数与普通函数的区别
this指向不同,箭头函数的this在定义的时候继承于外层第一个普通函数的this
不可以当作构造函数,也就是说,不可以使用 new 命令
不可以使用 arguments 对象,用 Rest 参数代替
不可以使用 yield 命令,因此箭头函数不能用作 Generator 函数
箭头函数不能通过call()、apply()、bind()方法直接修改它的this指向。
箭头函数没有prototype(原型),所以箭头函数本身没有this
单页面应用与多页面应用有什么区别?
单页面应用(SPA)和多页面应用(MPA)是两种常见的Web应用程序架构。它们有如下区别:
页面切换方式:SPA通常只有一个HTML文件,通过JavaScript在一个页面中动态地切换不同的内容。而MPA则包含多个HTML文件,每个页面都是独立的。
加载速度:SPA在第一次加载时需要下载整个应用程序的JavaScript代码和相关资源,但随后的页面切换不需要重新加载整个页面而只需要更新部分内容,因此页面切换速度较快。相比之下,MPA需要在每次页面切换时重新下载整个页面的HTML、CSS和JavaScript文件,因此页面切换速度相对较慢。
SEO优化: SPA页面中只有一个HTML文件,所有内容都由JS渲染,搜索引擎爬虫难以抓取其内容,因此SEO比MPA相对困难。
开发体验:SPA使用前端框架如Vue.js或React.js实现,可以使用组件化开发的方式提高代码可维护性;而MPA则需要在后端进行模板渲染,开发方式上略显陈旧。
用过什么前端JS框架?为什么用这些框架?
用过vue,node.js
用vue是因为它的组件化编程,大大增加了代码的复用性
用node.js是因为它能作为后台服务器启动,直接操作数据库
平时是如何学习的?
我会在周日拿出几个小时总结一些技术上的经验
每天晚上也会对自己一天中的工作做一些回顾
对自己的未来有哪些规划?
打算先多工作几年,积累一下经验,
等工作五年以后,工作能力达到了某个层次以后再考虑回归家庭。
vue优点?
轻量级框架:
只关注视图层,是一个构建数据的视图集合,大小只有几十kb;
简单易学:
国人开发,中文文档,不存在语言障碍 ,易于理解和学习;
双向数据绑定:
保留了angular的特点,在数据操作方面更为简单;
组件化:
保留了react的优点,实现了html的封装和重用,在构建单页面应用方面有着独特的优势;
视图,数据,结构分离:
使数据的更改更为简单,不需要进行逻辑代码的修改,只需要操作数据就能完成相关操作;
虚拟DOM:
dom操作是非常耗费性能的, 不再使用原生的dom操作节点,极大解放dom操作,但具体操作的还是dom不过是换了另一种方式;
运行速度更快:
相比较与react而言,同样是操作虚拟dom,就性能而言,vue存在很大的优势。
vue父组件向子组件传递数据?
通过props
子组件像父组件传递事件?
$emit方法
v-show和v-if指令的共同点和不同点?
共同点:都能控制元素的显示和隐藏;
不同点:实现本质方法不同。
v-show本质就是通过控制css中的display设置为none,控制隐藏,只会编译一次;
v-if是动态的向DOM树内添加或者删除DOM元素,若初始值为false,就不会编译了。而且v-if不停的销毁和创建比较消耗性能。
总结:
如果要频繁切换某节点,使用v-show(切换开销比较小,初始开销较大)。
如果不需要频繁切换某节点使用v-if(初始渲染开销较小,切换开销比较大)。
如何让CSS只在当前组件中起作用?
在组件中的style前面加上scoped
<keep-alive></keep-alive>
的作用是什么?
keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。
如何获取dom?
ref=“domName” 用法:this.$refs.domName
说出几种vue当中的指令和它的用法?
v-model双向数据绑定;
v-for循环;
v-if v-show 显示与隐藏;
v-on事件;v-once: 只绑定一次。
vue-loader是什么?使用它的用途有哪些?
vue文件的一个加载器,将template/js/style转换成js模块。
用途:js可以写es6、style样式可以scss或less、template可以加jade等
为什么使用key?
需要使用key来给每个节点做一个唯一标识,Diff算法就可以正确的识别此节点。
作用主要是为了高效的更新虚拟DOM。
axios及安装?
请求后台资源的模块。npm install axios --save装好,
js中使用import进来,然后.get或.post。返回在.then函数中如果成功,失败则是在.catch函数中。
v-model
v-model 是Vue框架的一种内置的API指令,本质是一种语法糖写法。
它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理
为什么使用v-model?
v-model指令可以在表单 input、textarea以及select元素上创建双向数据绑定它会根据控件类型自动选取正确的方法来更新元素。
尽管有些神奇,但 v-model 本质上不过是语法糖,它负责监听用户的输入事件来更新数据,并在某种极端场景下进行一些特殊处理;
什么场景下会使用v-model?
表单提交是开发中非常常见的功能,也是和用户交互的重要手段:比如用户在登录、注册时需要提交账号密码;
比如用户在检索、创建、更新信息时,需要提交一些数据;
这些都要求我们可以在代码逻辑中获取到用户提交的数据,我们通常会使用v-model指令来完成;
示例:v-model的基本使用
v-model的原理
官方有说到,v-model的原理其实是背后有两个操作:
v-bind绑定value属性的值;
v-on绑定input事件监听到函数中,函数会获取最新的值赋值到绑定的属性中;
computed与watch的区别
computed支持缓存,只有依赖的数据发生了变化,才会重新计算
watch不支持缓存,数据变化时,它就会触发相应的操作
computed不支持异步,当Computed中有异步操作时,无法监听数据的变化
watch支持异步监听
computed与methods的区别
1.括号
methods属性内的方法调用可以加括号
而computed属性内的方法调用不能加括号
如下所示:
<body>
<div id="app">
<h2>{{getFullName()}}</h2>
<h2>{{fullName}}</h2>
</div>
<script>
Vue.config.productionTig = false;
const app = new Vue({
el:"#app",
data(){
return {
firstName:"牛",
lastName:"顿"
}
},
methods:{
getFullName(){
return this.firstName + this.lastName;
}
},
computed:{
fullName(){
return this.firstName +this.lastName;
}
}
})
</script>
</body>
如下所示,computed加括号会报错
<div id="app">
<h2>{{getFullName()}}</h2>
<h2>{{fullName()}}</h2>
</div>
2.缓存
computed计算属性有缓存,同样代码只执行一次
methods没有缓存,需要执行多次。
所以计算属性效率更高。
slot是什么?有哪几种?作用是什么?
定义
插槽(slot)是一种占位符,可以用来声明在父组件模板中的子组件的位置。通过插槽,子组件可以在父组件中设置公共的布局结构,让父组件和子组件之间实现更好的解耦。
分类
具名插槽和作用域插槽
具名插槽用于将内容分发到组件内部的指定位置
作用域插槽则允许我们在父组件模板中传递数据到子组件中进行复杂的渲染逻辑
如何使用
具名插槽
首先,在父组件中声明一个具名插槽:
<template>
<div>
<h1>我是父组件</h1>
<!-- 声明一个名为 header 的插槽 -->
<slot name="header"></slot>
<p>这是父组件自己的内容</p>
<!-- 声明一个名为 footer 的插槽 -->
<slot name="footer"></slot>
</div>
</template>
然后,在子组件中插入具名插槽:
<template>
<div>
<h2>我是子组件</h2>
<slot name="header">
<!-- 如果没有插入 header 插槽的具体内容,
则默认显示这里的内容 -->
<p>这是默认的 header 内容</p>
</slot>
<p>这是子组件自己的内容</p>
<slot name="footer"></slot>
</div>
</template>
作用域插槽
作用域插槽可以向子组件传递数据,让子组件可以自定义渲染逻辑。
在父组件中声明一个作用域插槽:
<template>
<div>
<h1>我是父组件</h1>
<slot name="header" v-bind:data="data"></slot>
</div>
</template>
<script>
export default {
data() {
return {
data: 123,
};
},
};
</script>
在子组件中使用作用域插槽:
<template>
<div>
<h2>我是子组件</h2>
<slot name="header" v-bind:data="data">{{ data }}</slot>
</div>
</template>
<script>
export default {
props: ["data"],
};
</script>
在父组件中使用作用域插槽并传递数据:
<template>
<div>
<my-component>
<!-- 使用 v-slot 或者 # 号可以将作用域插槽绑定到对应的数据 -->
<template v-slot:header="props">
<p>{{ props.data }}</p>
</template>
</my-component>
</div>
</template>
v-on 指令
v-on用法
v-on 指令用于绑定事件监听器,v-on 指令的简写形式为 @event。
v-on 指令可以支持同时写多个事件监听器,多个事件监听器的简写形式为 v-on={@event1:handler1, @event2:handler2}。
v-on 指令支持原生 JavaScript 的所有的事件,并且支持参数传递。
vue中常见的事件修饰符及其作用?
v-on .stop 阻止事件冒泡。
v-on .prevet 阻止事件的默认行为。
v-on .capture 添加事件侦听器,使用事件捕获模式。
v-on .self 只当事件在该元素本身触发时,触发回调。
v-on .once 事件只触发一次。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>v-on补充</title>
</head>
<body>
<div id="app">
<input type="button" value="点击" @click="doIt(666,'继续写Vue')">
<input type="text" @keyup.enter="sayHi">
</div>
<!-- 1.开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el:"#app",
methods: {
doIt:function(p1,p2){
console.log("前端Vue开发");
console.log(p1);
console.log(p2);
},
sayHi:function(){
alert("hello vue");
}
},
})
</script>
</body>
</html>
Vue的基本原理
基本原理是响应式编程
包括两方面:
通过虚拟dom进行视图更新
通过模板引擎进行数据绑定
虚拟dom是什么?
虚拟dom本质上是一个js对象,在vue中,每个组件都有一个render函数,每个render函数都会返回一个虚拟dom树,这意味着每个组件都对应着一颗虚拟dom树
为什么需要虚拟dom?
如果在渲染时,直接使用真实dom,由于真实dom的创建、更新、插入会带来大量的性能消耗,从而就会极大地降低渲染效率,因此,vue在渲染时,使用虚拟dom来替代真实dom主要是解决渲染效率的问题
虚拟dom里面会用到diff算法,这个算法如果发现实际上没有新增10条,而是新增了两条,就会只把两条渲染到页面上去。
mvc 和mvvm区别
model 和 view 分别是什么?
看字面意思就可以知道
mvc 和 mvvm 中
mv是一样的,剩下的,一个是c,一个是vm
先说mv,这是两个东西
m 是 model ,是指数据
v 是 view ,是指视图
一个是后端的数据,一个是前端的视图
按理说,用户在页面上操作,view会变,然后model就要跟着变。
比如一个计数器的功能,本来是0,用户点击+1之后,数据就变为1了,结果那一栏就显示为1了。变化流程如下:
view → model → view
引入controller 和 viewModel
这样说来,只要有v 和m 这两个就好了。
为什么还要有c 和 vm 呢?
因为 + 1 这个操作要有人做。
c是controller的意思,代表控制器,里面主要是写业务的,它就负责做+1这个逻辑。
vm是viewModel的意思,代表视图模型
它本质上是一种连接view和model的桥梁。因为,Model层中的数据往往是不能直接跟View交互的。
就像vue中的{{ }}这个语法一样,是双向数据绑定的,数据一变,显示就变了。
下面这句话特别重要
MVVM并不是用VM完全取代了C,ViewModel存在目的在于抽离Controller中展示的业务逻辑,而不是替代Controller,其它视图操作业务等还是应该放在Controller中实现。
VUE 中的双向数据绑定是怎么实现的?
这个知识点比较难,要想完全掌握不太现实,面试也不会问太细。
下面的知识点已经为最浓缩版本,需要全部记住,包括英文单词。
双向数据绑定有两方面
页面有操作,引起数据改变
这个是通过数据劫持实现的。
数据劫持其实就是js中添加了监听,利用addEventListener函数将要绑定的数据保存到变量中,然后将变量中的数据不断地保存到documentFragment这个文档碎片模型中,最后将文档碎片模型渲染到页面上
数据变了,引起页面上显示的数值改变
首先我们需要拦截data对象中的所有属性
这样当页面数据发生改变
我们会在Object.defineProperty函数中的setter函数中监听到数据变化并拿到最新的数据
当获取到最新数据后,通过发布订阅模式来发布成功的消息,当有订阅者监听到消息发布后,就会更新dom元素,渲染页面
请简述 HTTPS 的工作原理和优点
HTTPS是一种基于HTTP协议的加密传输协议,比http更安全
一般https的请求在发起的时候需要添加证书
添加证书可以使用openssl生成一个自签名的证书,并将其添加到本地的信任列表中
请简述浏览器缓存机制,并说明强缓存和协商缓存的区别
浏览器缓存是指浏览器将一些网页资源(如图片、CSS、JavaScript等)保存在本地的缓存中,以便后续访问同一资源时可以直接从本地获取,而不必再次从服务器下载。浏览器缓存的机制分为强制缓存和协商缓存两种。
强制缓存:当浏览器第一次请求一个资源时,服务器会将该资源的过期时间或最大缓存时间等相关信息一并返回给浏览器,浏览器收到响应后会将该信息存储到本地缓存中。当再次请求该资源时,浏览器首先检查该资源是否存在本地缓存中,若存在且未过期,则直接从本地缓存中获取,并返回200状态码,不用请求服务器。如果已过期,则重新向服务器请求,服务器会根据请求的header中的信息来判断是否返回最新的数据。
协商缓存:当强制缓存失效了,浏览器会向服务器发送一个请求,请求中会携带上一次请求该资源时服务器返回的相关信息,比如If-Modified-Since,If-None-Match等。服务器收到请求后,会根据这些信息来验证该资源是否有更新。如果资源没有更新,则返回304状态码,浏览器可直接从本地缓存中获取该资源,否则返回新的资源。
区别:强制缓存和协商缓存的区别在于是否向服务器发送请求。强制缓存不会向服务器发送请求,而是直接从缓存中获取资源;而协商缓存需要向服务器发送请求,但是相比强制缓存,协商缓存能够更加准确的判断出内容是否更新,避免了更新后仍然使用旧缓存的问题。
请问你如何保证前端代码的可维护性、复用性和扩展性?
1.重复的代码抽象成统一的方法
2.重复的功能抽象成统一的组件
3.多写注释
element UI都有哪些组件?
基础组件:Button、Input、Checkbox、DatePicker、TimePicker
数据展示组件:Progress、Tree
弹出层组件:MessageBox
echarts 常用方法
init 初始化 Echarts 实例
setOption 设置 Echarts 实例的配置项
resize()
调整 Echarts 实例的大小,当容器尺寸发生变化时需要手动调用该方法刷新图表。
dispose(): void
销毁 Echarts 实例,释放资源,避免内存泄漏。