简单整理前端笔记
数组原生的方法造成的数据更新 可以被vue监听到 push() pop()
使用this.$set 来解决无法监听数组属性内部变化的问题
vue初始化页面闪动 页面未被解析之前就展示再dom中 使用v-cloak将message 包起来
使用vue开启keep-alive缓存的页面
if
="$route.meta.keepAlive"
>` 页面的代码
meta:{keepAlive:``true``}
使用element ui 干过什么东西
使用layout布局
使用混合布局 响应式布局
使用container布局容器哦 el-header el-aside el-main el-footer
vue中的单向数据流
父级 prop 的更新会向下流动到子组件中,每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值
- 意义 防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。
- 解决办法: 1、定义一个局部变量,并用 prop 的值初始化它。
2、定义一个计算属性,处理 prop 的值并返回。
vue中监听不到数组长度变化的原因
object.property的原因可以检测到通过索引改变数组操作的变化,但是vue并没有进行实现 ,主要是因为性能的代价和用户体验的收益不成正比
vue中的v-for v-if不能连用
1.v-for比v-if优先,如果每一次都需要遍历整个数组,将会影响速度,尤其是当之需要渲染很小一部分的时候。
如果连用的话会把 v-if 给每个元素都添加一下,会造成性能问题。
一般时候把v-if放在外层,如果不符合就不去执行了。
也可以使用计算属性computed来代替v-if
vue组件中通信的方式
-
父子组件之间进行通信
- 父传子 父组件使用 v-bind 子组件使用props属性进行接受
- 子传父 子组件使用$emit 发送 父组件v-on进行接受
-
使用refs-$ref
-
parent/children
-
全局组件之间的通信
-
任意组件 使用 $emit进行发送数据 使用 on进行接受
-
使用vuex 状态管理工具
- 注册全局组件$store 将共享数据放入state中进行存储
- 使用getters进行数据的获取
- 使用mutations进行全局变量的更改 同步数据的操作 使用 this.$store.commit 提价数据修改
- 使用actions进行异步数据操作 this.$store.dispatch(“方法名”,数据)
computed和watch的区别
computed
计算属性,依赖其他属性,当其他属性改变的时候下一次获取computed值时也会改变,computed的值会有缓存
watch
类似于数据改变后的回调
如果想深度监听的话,后面加一个deep:true
如果想监听完立马运行的话,后面加一个immediate:true
vue中的nexttick
vue\实现响应式并不是在数据变化之后dom立即变化而是在同意时间循环中所有的数据变化完成之后 再进行dom统一更新
-
-
1.在Vue生命周期的created()钩子函数进行DOM操作一定要放到Vue.nextTick()的回调函数中
-
2.在数据变化后要执行的某个操作,而这个操作需要使用随数据改变而改变的DOM结构的时候,这个操作都应该放进Vue.nextTick()的回调函数中。
-
- 父
beforeCreate
->父created
->父beforeMount
->子beforeCreate
->子created
->子beforeMount
->子mounted
->父mounted
- 父
router中的钩子函数
- beforeEach
- 参数有
- to(Route路由对象)
- from(Route路由对象)
- next(function函数) 一定要调用才能进行下一步
- 参数有
- afterEach
- beforeRouterLeave
loader和plugin的区别是什么?
loader
loader是用来解析非js文件的,因为Webpack原生只能解析js文件,如果想把那些文件一并打包的话,就需要用到loader,loader使webpack具有了解析非js文件的能力
plugin
用来给webpack扩展功能的,可以加载许多插
router 的原理
原理是通过改变url 在不重新请求页面的情况下更新视图
更新视图但不重新请求页面,是前端路由原理的核心之一,目前在浏览器环境中这一功能的实现主要有2种方式,Hash模式和History模式:
(1)利用URL中的hash("#");
(2)利用History interface在HTML5中新增的方法;
1、Hash模式:
hash(#)是URL 的锚点,代表的是网页中的一个位置,单单改变#后的部分,浏览器只会滚动到相应位置,不会重新加载网页,也就是说 #是用来指导浏览器动作的,对服务器端完全无用,HTTP请求中也不会不包括#;同时每一次改变#后的部分,都会在浏览器的访问历史中增加一个记录,使用”后退”按钮,就可以回到上一个位置;
2、History模式: (不怕前进不怕后退 就怕刷新)
//HTML5 History API提供了一种功能,能让开发人员在不刷新整个页面的情况下修改站点的URL,就是利用 //history.pushState API 来完成 URL 跳转而无须重新加载页面;
this.$router.push("/local")
this.$router.replace("/cal")
window.history.pushState(stateObject, title, URL)
window.history.replaceState(stateObject, title, URL)
通常情况下,我们会选择使用History模式,原因就是Hash模式下URL带着‘#’会显得不美观;但实际上,这样选择一不小心也会出问题;比如:
但当用户直接在用户栏输入地址并带有参数时:
Hash模式:xxx.com/#/id=5 请求地址为 xxx.com,没有问题;
History模式: xxx.com/id=5 请求地址为 xxx.com/id=5,如果后端没有对应的路由处理,就会返回404错误;
history模式下的原生api
window.history.pushState(state, title, url)
// state:需要保存的数据,这个数据在触发popstate事件时,可以在event.state里获取
// title:标题,基本没用,一般传 null
// url:设定新的历史记录的 url。新的 url 与当前 url 的 origin 必须是一樣的,否则会抛出错误。url可以是绝对路径,也可以是相对路径。
//如 当前url是 https://www.baidu.com/a/,执行history.pushState(null, null, './qq/'),则变成 https://www.baidu.com/a/qq/,
//执行history.pushState(null, null, '/qq/'),则变成 https://www.baidu.com/qq/
window.history.replaceState(state, title, url)
// 与 pushState 基本相同,但她是修改当前历史记录,而 pushState 是创建新的历史记录
window.addEventListener("popstate", function() {
// 监听浏览器前进后退事件,pushState 与 replaceState 方法不会触发
});
window.history.back() // 后退
window.history.forward() // 前进
window.history.go(1) // 前进一步,-2为后退两步,window.history.lengthk可以查看当前历史堆栈中页面的数量
路由传参
vue-router传递参数分为两大类
- 编程式的导航 router.push
- this. r o u t e . q u e r y . q u e r y I d − − − 使 用 p u s h : t h i s . route.query.queryId --- 使用push:this. route.query.queryId−−−使用push:this.router.push({ path: ‘/news’, query: { userId: 123 }});
- {{this.KaTeX parse error: Expected 'EOF', got '}' at position 20: …e.params.userId}̲ -- this.router.push({ name: ‘news’, params: { userId: 123 }}
- 声明式的导航
- click to news page
- click to news page
虚拟DOM的优缺点
- 缺点
- 首次渲染大量DOM时,由于多了一层虚拟DOM的计算,会比innerHTML插入慢
- 优点
- 减少了dom操作,减少了回流与重绘
- 保证性能的下限,虽说性能不是最佳,但是它具备局部更新的能力,所以大部分时候还是比正常的DOM性能高很多的
vue 中key的作用
- key
- key主要用在虚拟Dom算法中,每个虚拟节点VNode有一个唯一标识Key,通过对比新旧节点的key来判断节点是否改变,用key就可以大大提高渲染效率,这个key类似于缓存中的etag。
使用axios配置跨域的解决方案
-
将在app.vue中导入使用axios ,将axios挂载在vue的原型对象上
-
新建js文件配置baseURL /api
-
在全局配置文件中vue.configure.js中修改相关的配置
-
设置纯前端配置代理的方式解决跨域
proxy: {
'/api': {
// 此处的写法,目的是为了 将 /api 替换成 https://www.baidu.com/
target: 'https://www.baidu.com/',
// 允许跨域
changeOrigin: true,
ws: true,
pathRewrite: {
'^/api': ''
}
} }
this.$axios.get('/').then(response => {
if (response.data) {
console.log(response.data) } }).catch(err => { alert('请求失败') })
- 最后一步 修改axios的使用方法
使用下拉刷新来实现
而我们下拉刷新的过程主要是用到了触碰屏幕(touchstart),开始下拉(touchmove),松手(touchend)。
// 下拉刷新
_this.outerScroller.addEventListener(
'touchstart',
function (event) {
var touch = event.targetTouches[0];
// 把元素放在手指所在的位置
_this.touchStart = touch.pageY;
// event.preventDefault(); // 阻止浏览器默认下滑事件
},
false
);
_this.outerScroller.addEventListener(
'touchmove',
function (event) {
var touch = event.targetTouches[0];
_this.scroll.style.top =
_this.scroll.offsetTop + touch.pageY - _this.touchStart + 'px';
_this.touchStart = touch.pageY;
_this.touchDis = touch.pageY - _this.touchStart;
if (_this.scroll.offsetTop > 0 && document.body.scrollTop < 50) {
document.body.addEventListener('touchmove', _this.preEvent, {
passive: false
}); // passive 参数不能省略,用来兼容ios和android
_this.emptyDiv.style.marginTop =
Number(_this.scroll.style.top.replace(/\s+|px/gi, '')) + 20 + 'px'; // 让下拉的父级高度等于下滑部分+下滑距离,让整体呈现下拉的感觉
} else {
return;
}
if (_this.scroll.offsetTop >= 80) {
// 限制下拉的距离
_this.scroll.style.top = '80px';
}
},
false
);
_this.outerScroller.addEventListener(
'touchend',
function (event) {
_this.touchStart = 0;
var top = _this.scroll.offsetTop;
var num = _this.scroll.style.top.replace(/\s+|px/gi, ''); // 将top值转成数值
if (num < 0) {
// 当上滑到顶部的时候,不超过边界
_this.scroll.style.top = '0px';
return;
}
if (top > 40) refresh();
if (top > 0) {
var time = setInterval(function () {
_this.scroll.style.top = _this.scroll.offsetTop - 2 + 'px';
_this.emptyDiv.style.marginTop =
Number(_this.scroll.style.top.replace(/\s+|px/gi, '') + 20) +
'px'; // 让下拉的父级高度等于下滑部分+下滑距离,让整体呈现下拉的感觉
if (_this.scroll.offsetTop <= 0) clearInterval(time);
}, 1);
}
/* var time = setTimeout(function(){
scroll.style.top = scroll.offsetTop -2+'px';
emptyDiv.style.height = Number(360) + Number(scroll.style.top.replace(/\s+|px/gi,"")) + 'px'; // 让下拉的父级高度等于下滑部分+下滑距离,让整体呈现下拉的感觉
if(scroll.offsetTop<=0)clearTimeout(time);
time();
},1)
while(top>0){
time();
} */
// event.stopPropagation();
// window.event.returnValue = false;
document.body.removeEventListener('touchmove', _this.preEvent, {
passive: false
}); // passive 参数不能省略,用来兼容ios和android
},
false
);
function refresh () {
console.log('下拉刷新');
}
js判断类型
typeof
缺点:typeof null的值为Object,无法分辨是null还是Object
instanceof
缺点:只能判断对象是否存在于目标对象的原型链上
constructor
Object.prototype.toString.call()
一种最好的基本类型检测方式 Object.prototype.toString.call() ;它可以区分 null 、 string 、
boolean 、 number 、 undefined 、 array 、 function 、 object 、 date 、 math 数据类型。
缺点:不能细分为谁谁的实例
js onload show
onload 在页面加载时出发 一个页面只会调用一次 onshow在页面进行显示切换的时候出发
比如从当前页面跳转到另一个页面 返回时不会触发onload 会触发onshow
js手写一个new
- 创建一个新对象
- 使新对象的
__proto__
指向原函数的prototype
- 改变this指向(指向新的obj)并执行该函数,执行结果保存起来作为result
- 判断执行函数的结果是不是null或Undefined,如果是则返回之前的新对象,如果不是则返回res
// 手写一个new
function myNew(fn, ...args) {
// 创建一个空对象
let obj = {}
// 使空对象的隐式原型指向原函数的显式原型
obj.__proto__ = fn.prototype
// this指向obj
let result = fn.apply(obj, args)
// 返回
return result instanceof Object ? result : obj
}
伪类和为元素的区别
-
伪类本质上是为了弥补常规CSS选择器的不足,以便获取到更多信息;
-
伪元素本质上是创建了一个有内容的虚拟容器;
-
CSS3中伪类和伪元素的语法不同;
-
可以同时使用多个伪类,而只能同时使用一个伪元素;
选择器优先级
1. !important
在属性后面写上这条样式,会覆盖掉页面上任何位置定义的元素的样式。
2. 行内样式,在style属性里面写的样式。 1000
3. id选择器 100 4. class选择器10 伪类 权值为10 5. 标签选择器 伪元素 1
\6. 通配符选择器*
7. 浏览器的自定义属性和继承
webSocket
ajax 返回的状态
0 - (未初始化)还没有调用send()方法
1 - (载入)已调用send()方法,正在发送请求
2 - (载入完成)send()方法执行完成,已经接收到全部响应内容
3 - (交互)正在解析响应内容
4 - (完成)响应内容解析完成,可以在客户端调用了
js为什么要设计成单线程、
js是作为浏览器的脚本语言,主要是实现用户与浏览器的交互,以及操作dom;这决定了它只能是单线程,否则会带来很复杂的同步问题。 举个例子:如果js被设计了多线程,如果有一个线程要修改一个dom元素,另一个线程要删除这个dom元素,此时浏览器就会一脸茫然,不知所措。所以,为了避免复杂性,从一诞生,JavaScript就是单线程,这已经成了这门语言的核心特征,将来也不会改变
实现sum的无线累加
function sum(a){
let temp = function(b){
return sum(a+b)
}
// temp.toString这里写成temp.valueOf也可以
temp.toString = function(){
return a
}
return temp
}
let ans = sum(1)(2)(3)
console.log(ans)
jsmap和foreach的区别
- 能用
forEach()
做到的,map()
同样可以。反过来也是如此。 map()
会分配内存空间存储新数组并返回,forEach()
不会返回数据。forEach()
允许callback
更改原始数组的元素。map()
返回新的数组
promise的原理
基于上面的应用场景发现promise
可以有三种状态,分别是pedding
、Fulfilled
、 Rejected
。
Pending Promise
对象实例创建时候的初始状态
Fulfilled
可以理解为成功的状态
Rejected
可以理解为失败的状态
- 构造一个
Promise
实例需要给Promise
构造函数传入一个函数。传入的函数需要有两个形参,两个形参都是function
类型的参数。分别是resolve
和reject
。 Promise
上还有then
方法,then
方法就是用来指定Promise
对象的状态改变时确定执行的操作,resolve
时执行第一个函数(onFulfilled),reject
时执行第二个函数(onRejected)- 当状态变为
resolve
时便不能再变为reject
,反之同理。
async awit 的实现一案例
本质上async还是一个promise函数 是将promise。then()这个异步操作的回调函数放在了awit之后进行执行
js实现异步操作的发展史
js promise。all的实现
class MyPromise2 {
constructor(executor) {
// 规定状态
this.state = "pending"
// 保存 `resolve(res)` 的res值
this.value = undefined
// 保存 `reject(err)` 的err值
this.reason = undefined
// 成功存放的数组
this.successCB = []
// 失败存放的数组
this.failCB = []
let resolve = (value) => {
if (this.state === "pending") {
this.state = "fulfilled"
this.value = value
this.successCB.forEach(f => f())
}
}
let reject = (reason) => {
if (this.state === "pending") {
this.state = "rejected"
this.value = value
this.failCB.forEach(f => f())
}
}
try {
// 执行
executor(resolve, reject)
} catch (error) {
// 若出错,直接调用reject
reject(error)
}
}
then(onFulfilled, onRejected) {
if (this.state === "fulfilled") {
onFulfilled(this.value)
}
if (this.state === "rejected") {
onRejected(this.value)
}
if (this.state === "pending") {
this.successCB.push(() => { onFulfilled(this.value) })
this.failCB.push(() => { onRejected(this.reason) })
}
}
}
//手写实现一个promise.all函数
Promise.all = function (promises) {
let list = []
let count = 0
function handle(i, data) {
list[i] = data
count++
if (count == promises.length) {
resolve(list)
}
}
return Promise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
promises[i].then(res => {
handle(i, res)
}, err => reject(err))
}
})
}
js实现键名的替换
var list = [{ id: 'a', title: 'A'},
{ id: 'b', title: 'B', children: [{ id: 'c', title: 'C' }, { id: 'd', title: 'D' }]}]
//实现一个函数 将对象中的所有id变为code 将title 变为name
function conve(list){
for( let i in list){
if(list[i].id!=null){
list[i].code=list[i].id;
delete list[i].id
}else if (list[i].title!=null){
list[i].title=list[i].name;
delete list[i].title
}else if(list[i].children!=null){
conve(list[i])
} }
return list}console.log(conve(list))
//实现一个单词的逆序
function nixu(str){ return str.split(" ").reverse().join(" ")}
//实现数字金额的格式化
function formatter(number){} //小数部分保留两位小数 整数部分分三位增加逗号
#手写map apply
js中0.2+0.1》0.3为什么
- js中的浮点数用64位固定的长度来表示
- 52为表示位数
- 0.1转换为二进制是一个无限循环的小数0.00000110001100011000 在转换为十进制就不是0.1了
简单描述下this
//箭头函数体中的 this 对象,是定义函数时的对象,而不是使用函数时的对象
//每一个函数或对象的建立都是一个新的执行上下文
//构造函数的属性全部都是挂载在原型链上面
//当构造函数实例化对象调用的也是继承与原型的属性与方法
//构造函数里面的方法嵌套函数会改变this指向window需要先用变量存储this
//在对象里调用的this是指向对象的
//setInterval(()=>{console.log(this)},1000)维护this一致
// setInterval(function(){console.log(this)},1000)this是window
//不建议在定义函数方法且方法包含this的时候使用箭头函数
————————————————
版权声明:本文为CSDN博主「坚持学习前端日记」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_43505774/article/details/105385360
js设计模式
-
单例模式 不管创建多少个对象都仅仅只有一个实例
-
单点登录的登录按钮 无论点击多少次登录 浮窗只允许被创建一次
-
function creatSingleton() { var obj = null // 核心思想:实例如已经创建过,直接返回 if (!obj) { obj = xxx } return obj }
-
var Single = (function () {
var instance = null
function Single(name) {
this.name = name
}
return function (name) {
if (!instance) {
instance = new Single(name)
}
return instance
}
})()
var oA = new Single('hi')
var oB = new Single('hello')
console.log(oA);
console.log(oB);
console.log(oB === oA);
-
工厂模式 代替new创建一个对象,且对象像工厂制作一样 批量制作属性相同的实例对象
- 构造函数和创建者分离,对new操作进行封装
- 符合开放封闭原则
-
function Animal(o) { var instance = new Object() instance.name = o.name instance.age = o.age instance.getAnimal = function () { return "name:" + instance.name + " age:" + instance.age } return instance } var cat = Animal({name:"cat", age:3}) console.log(cat);
手写实现eventbus(发布订阅模式)
class Observer {
constructor() {
this.events={}//事件中心
}
publish(eventName,...args) {//发布=>调用事件中心中对应的函数
if (this.events[eventName])
this.events[eventName].forEach(cb=>cb.apply(this,args))
}
subscribe(eventName,callback) {//订阅=>向事件中心中添加事件
if (this.events[eventName]) {
this.events[eventName].push(callback)
} else {
this.events[eventName]=[callback]
}
}
unSubscribe(eventName,callback) {//取消订阅
if (events[eventName])
events[eventName]=events[eventName].filter(cb=>cb!==callback)
}
}
class EventBus {
constructor(){
this.eventContainer = this.eventContainer || new Map() //用一个容器存放事件
}
on(type,callback){
if(!this.eventContainer.has(type)){
//如果容器里面没有这种类型的事件,就增加
this.eventContainer.set(type,callback)
}
}
off(type){
if(this.eventContainer.has(type)){
this.eventContainer.delete(type)
}
}
emit(type){
let fn = this.eventContainer.get(type)
fn.apply(this,[...arguments].slice(1))
}
}
let ev = new EventBus()
ev.on('myevent',name=>{console.log('hello,',name)})
ev.emit('myevent','jack')
编程题 实现数组的全排列
闭包和立即执行函数的区别
立即执行函数和闭包没有关系,虽然两者会经常结合在一起使用,但两者有本质的不同
立即执行函数只是函数的一种调用方式,只是声明完之后立即执行,这类函数一般都只是调用一次(可用于单例对象上),调用完之后会立即销毁,不会占用内存
闭包则主要是让外部函数可以访问内部函数的作用域,也减少了全局变量的使用,保证了内部变量的安全,但因被引用的内部变量不能被销毁,增大了内存消耗,使用不当易造成内存泄露
原文链接:https://blog.csdn.net/Liu_yunzhao/article/details/90641956
ajax 和 jsonp的调用
jsonp('http://xxxxxxxx',{id:123},data=>{ //获取数据后的操作 })
ajax('get','https://www.baidu.com',{id:15},data=>console.log(data))
统计一个复杂对象值中字符匹配的个数
funciton fuza(obj){
var res=0;
for(let i in obj){
if(obj[i] instaceof Object){
fuza(obj[i])
}else if(obj[i] instaceof Array){
fuza(obj[i])
}else{
continue
}
}
}
rgba透明度,opacity透明度
rgba()和opacity都能实现透明效果,但最大的不同是opacity作用于元素,以及元素内的所有内容的透明度,而rgba()只作用于元素的颜色或其背景色。(设置rgba透明的元素的子元素不会继承透明效果!)比如,我们写透明的黑色部分都是用opcity(0.5),但这带出来一个问题就是如果你在这一div上写字的话,然后那个字体也会变成透明色。所以我们采取rgba的样式写,前面三个数字分别对应r,g,b,的三种颜色,第四位的数字对应的是透明的系数
设置文本溢出显示为省略号
- 单行文本
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap
-
多行文本
#txt{ display: inline-block; height: 40px; width: 250px; line-height: 20px; overflow: hidden; font-size: 16px; } .t:after{ display: inline; content: "..."; font-size: 16px; }
块级元素和行内元素的区别
-
对于行内元素设置 padding和margin也是有效的,但是只有margin-left和margin-right是有效的 上下内边距和外边距只是在内容山进行了撑开 对盒子外的元素并没有影响
-
行内元素会在一条直线上排列,都是同一行的,水平方向排列。
块级元素各占据一行,垂直方向排列。块级元素从新行开始结束接着一个断行。
2.块级元素可以包含行内元素和块级元素。行内元素不能包含块级元素。
3.行内元素与块级元素属性的不同,主要是盒模型属性上。
行内元素设置width无效,height无效(可以设置line-height),margin上下无效,padding上下无效。
实现块级元素和行内元素居中的方法
行内元素和块级元素不同,对于行内元素,只需在父元素中设置text-align=center即可;
对于块级元素有以下几种居中方式:
1.将元素放置在table中,再将table的margin-left和margin-right设置成auto,将table居中,使在其之中的块级元素叶居中,但是这种方式不符合语义化标签的规范; (margin:0 auto)
2.将块级元素转换行内元素(通过设置display:inline)后再居中.这种方式使居中元素变成行内元素而致使无法设置宽高;
3.设置父元素float:left,position:relative,left:50%;子元素float:left,position:relative,left:-50%,利用相对布局的方式居中.上面三种方式各有优劣,依使用情景具体选择.
-
垂直居中的设置方法
1.对于知道高度的元素可以设置上下padding相等;
2.设置line-height和height相等
3.利用vertical-align,但是这属性只在tr,td中适用,故可将元素放置入table中在居中
css清除浮动的方式
浮动带来的副作用
父元素塌陷 行内元素为浮动元素让路 遮挡块状元素
\1. 使用空标签清除浮动。
这种方法是在所有浮动标签后面添加一个空标签 定义css clear:both. 弊端就是增加了无意义标签。
\2. 使用overflow。
给包含浮动元素的父标签添加css属性 overflow:auto; zoom:1; zoom:1用于兼容IE6。
\3. 使用after伪对象清除浮动。
该方法只适用于非IE浏览器。具体写法可参照以下示例。使用中需注意以下几点。一、该方法中必须为需要清除浮动元素的伪对象中设置 height:0,否则该元素会比实际高出若干像素;
可以给父元素设置overflow:auto或者hidden
引入css样式的方式
1 行内样式
2 head标签中写入style样式
3 外部的样式 - 通过link @import
- 1、链接式
margin 塌陷的问题
margin塌陷的问题 如果是同级元素 外边距小的会被外边距大的元素进行包围 解决的办法
父子元素 本身父元素的上边距为0 设置子元素的上边距后父元素会随着子元素一起掉下来
(1)同级元素:如果两个元素垂直方向有间距,只需要设置给一个元素,不要进行拆分。
(2)父子元素:让两个边距不要相遇,中间可以使用父元素border或padding将边距分隔开;更加常用的方法,父子盒模型之间的距离就不要用子元素的margin去设置,而是用父元素的padding挤出来。
css上下margin重叠的问题
- 内层元素添加 float 或者display
- 加一个inline元素
- overflow:hidden
- 内层元素使用绝对定位
- 养成良好的代码习惯 再设置 magin-bottm的时候给增加margin-top
1 <div style="background: red;">
2 <div style="margin-top:50px;float:left:display:inline-block;">margin</div>
3 </div>
1 <div style="background: red;padding-top:1px;">
2 <div style="margin-top:50px;">margin</div>
3 </div>
1 <div style="background: red;overflow:hidden;">
2 <div style="margin-top:50px;">margin</div>
3 </div>
css3新特性
\1. CSS3实现圆角(border-radius),阴影(box-shadow),
\2. 对文字加特效(text-shadow、),线性渐变(gradient),旋转(transform)
\3. transform:rotate(9deg) scale(0.85,0.90) translate(0px,-30px) skew(-9deg,0deg);// 旋转,缩放,定位,倾斜
\4. 增加了更多的CSS选择器 多背景 rgba
\5. 在CSS3中唯一引入的伪类是 ::selection.
\6. 媒体查询,多栏布局 @media screen and (max-width: 500px) {当窗口的宽度小于500px时将背景色进行修改}
\7. border-image
css中设置aligN-item 和align-content 的区别
可以看到与初始状态并没有区别,即在flex容器不设置高度并且子项只有一行时,align-content
属性是不起作用的
多行元素的情况下 当容器的高度不确定时 存在的align-items只是保证每项的元素进行居中
而align-content
是将整体的内容进行紧凑居中如下图
讲讲http缓存
https://www.jianshu.com/p/9c95db596df5
缓存分为强缓存和协商缓存
- 强缓存
在浏览器加载资源时,先看看cache-control里的max-age,判断数据有没有过期,如果没有直接使用该缓存 ,有些用户可能会在没有过期的时候就点了刷新按钮,这个时候浏览器就回去请求服务端,要想避免这样做,可以在cache-control里面加一个immutable.
public
允许客户端和虚拟服务器缓存该资源,cache-control中的一个属性
private
只允许客户端缓存该资源
no-cache
不允许强缓存,可以协商缓存
no-store
不允许缓存
- 协商缓存
浏览器加载资源时,没有命中强缓存,这时候就去请求服务器,去请求服务器的时候,会带着两个参数,一个是If-None-Match,也就是响应头中的etag属性,每个文件对应一个etag;另一个参数是If-Modified-Since,也就是响应头中的Last-Modified属性,带着这两个参数去检验缓存是否真的过期,如果没有过期,则服务器会给浏览器返回一个304状态码,表示缓存没有过期,可以使用旧缓存。
etag的作用
有时候编辑了文件,但是没有修改,但是last-modified属性的时间就会改变,导致服务器会重新发送资源,但是etag的出现就完美的避免了这个问题,他是文件的唯一标识
etag: '5c20abbd-e2e8'
last-modified: Mon, 24 Dec 2018 09:49:49 GMT
页面攻击
- xss脚本注入
不需要你做任何的登录认证,它会通过合法的操作(比如在url中输入、在评论框中输入),向你的页面注入脚本(可能是js、hmtl代码块等)。
防御
编码:对用户输入的数据进行HTML Entity 编码。把字符转换成 转义字符。Encode的作用是将$var等一些字符进行转化,使得浏览器在最终输出结果上是一样的。
过滤:移除用户输入的和事件相关的属性。
- csrf跨域请求伪造
在未退出A网站的前提下访问B,B使用A的cookie去访问服务器
防御:token,每次用户提交表单时需要带上token(伪造者访问不到),如果token不合法,则服务器拒绝请求 - sql脚本注入 ’ OR ‘1’='1 攻击者成功的向服务器提交恶意的SQL查询代码,程序在接收后错误的将攻击者的输入作为查询语句的一部分执行,
- 什么是ddos DDOS:分布式拒绝服务攻击(Distributed Denial of Service),简单说就是发送大量请求是使服务器瘫痪。DDos攻击是在DOS攻击基础上的,可以通俗理解,dos是单挑,而ddos是群殴,因为现代技术的发展,dos攻击的杀伤力降低,所以出现了DDOS,攻击者借助公共网络,将大数量的计算机设备联合起来,向一个或多个目标进行攻击。
作用域链和作用域
- 规定变量和函数的可使用范围称作作用域
- 每个函数都有一个作用域链,查找变量或者函数时,需要从局部作用域到全局作用域依次查找,这些作用域的集合称作作用域链
token 登录验证的过程
1、数据库密码字段存入的数据为MD5加密后的数据
2、第一次访问登录页面通过uuid生成一个loginkey并存入session
3、前端提交登录数据的密码构成: MD5(MD5(用户填写的密码)+loginkey) 传入后台
4、后台验证用户存在的情况下取出用户数据库数据进行验证:MD5(数据库密码+session中的loginkey) === 用户提交的密码(步骤三传过来的密码
-
表单验证==》调用分装好的函数==》经过请求拦截器,添加响应头==》代理转发==》得到接口调用之后的结果==》保存token到vuex
-
使用vuex的基本逻辑:数据放在state中,要修改数据则调用mutations
- 先在state中补充定义token
- 同时,要提供对应的用来修改token的mutation,以方便在用户登陆成功之后,去设置token
-
需要的话 token做持久化
- 在对token进行初始化的时候先从本地取一下,优先使用本地取到的值
- 在设置token的时候除了在vuex中存一份,在本地也同步存一份
- 在删除token的时候除了把vuex中的删除掉,把本地的也一并删除
http1.0和http1.1,还有http2有什么区别?
http0.9只能进行get请求
http1.0添加了POST,HEAD,OPTION,PUT,DELETE等
http1.1增加了长连接keep-alive,增加了host域,而且节约带宽
http2 多路复用,头部压缩,服务器推送
cpu的位数 与内存大小的关系(位数指的是同一时间内所能同时处理字长)
处理器的位数一般是指在同一时间中处理二进制数的位数,就是字长。通常称处理字长为8位数据的CPU叫8位CPU,32位CPU就是在同一时间内处理字长为32位的二进制数据。而内存是存储设备,一个存储单元可存储一串二进制代码,称这串二进制代码为一个存储字,这串二进制代码的个数叫作存储字长.存储字长可以是8位,16位或32位等.与内存无关的,放心吧。
开发实现移动端的自适应
-
即通过js操纵meta标签中的initial-scale(即网页初始缩放比例)属性即可。 一套css代码即可适应所有屏幕宽度不同的手机;
-
使用固定长度单位px,再使用js根据当前屏幕宽度与固定宽度计算比例,进行网页缩放,来实现移动端屏幕自适应
-
**一、**使用百分比长度单位,当前百分比长度单位一般如下:vw、vh、vm、em、rem、%,**优点:**一套css代码即可适应所有屏幕宽度不同的手机;
-
**vw:**相对于视口的宽度,视口被均分为100单位的vw;即将当前屏幕宽度均分为100份,1vw即为当前屏幕宽度的1%;**优点:**vw单位长度准确分明,常用此单位,推荐使用此单位。
-
**em:**相对长度单位。相对于当前对象内文本的字体尺寸。如当前对行内文本的字体尺寸未被人为设置,则相对于上一个父元素的默认字体尺寸。举例而言,浏览器默认字体大小为16px,在css中设置 于css中进行字体设置譬如:font-size1:4vw;,方可实现屏幕自适应。**基本不用此单位,**它的优点rem都有,但它是优先使用自身的字体大小,其次继承上一个父元素的字体大小
-
**rem:**相对长度单位,相对于根元素(即html元素)内文本的字体尺寸。rem继承且只继承html标签的字体大小。同样的,此单位若要用于屏幕自适应,需与vw配合使用设置根元素的字体大小。必须在css中进行字体设置:
html{font-size:4vw;}
方可实现屏幕自适应。**常用此单位,推荐使用此单位。**看到这里,相信很多朋友都会感到疑惑,明明直接使用vw单位即可实现自适应,为何要使用vw单位进行设置后来使用rem单位呢?原因很简单:便于计算。首先,设计师设计的移动端设计稿通常使用750px宽度(契合iphone678的屏幕宽度),前端工程师通常使用375px的网页宽度(在所有手机屏幕宽度中,它是最方便计算的宽度)。此时,1vw=3.75px;而4vw=15px;8vw=30px;那么请问,哪个单位更便于计算?由于30px与375px相除并非整数,我推荐使用15px(即1rem=4vw)
- em与rem的重要区别: 它们计算的规则一个是依赖父元素另一个是依赖根元素计**算
实现页面重定向的方法
- 使用html meta head 进行跳转
<meta http-equiv="refresh" content="5; url=http://www.dreamdu.com/" />
-
使用js location.href 属性进行跳转
-
location.href = "www.jd.com"
-
-
响应报文头
实现一个div的拖拽效果
var box = document.getElementsByClassName("box")[0]; //获取元素
var x, y; //鼠标相对与div左边,上边的偏移
var isDrop = false; //移动状态的判断鼠标按下才能移动
box.onmousedown = function(e) {
var e = e || window.event; //要用event这个对象来获取鼠标的位置
x = e.clientX - box.offsetLeft;
y = e.clientY - box.offsetTop;
isDrop = true; //设为true表示可以移动
}
document.onmousemove = function(e) {
//是否为可移动状态
if(isDrop) {
var e = e || window.event;
var moveX = e.clientX - x; //得到距离左边移动距离
var moveY = e.clientY - y; //得到距离上边移动距离
//可移动最大距离
var maxX = document.documentElement.clientWidth - box.offsetWidth;
var maxY = document.documentElement.clientHeight - box.offsetHeight;
//范围限定 当移动的距离最小时取最大 移动的距离最大时取最小
//范围限定方法一
/*if(moveX < 0) {
moveX = 0
} else if(moveX > maxX) {
moveX = maxX;
}
if(moveY < 0) {
moveY = 0;
} else if(moveY > maxY) {
moveY = maxY;
} */
//范围限定方法二
moveX=Math.min(maxX, Math.max(0,moveX));
moveY=Math.min(maxY, Math.max(0,moveY));
box.style.left = moveX + "px";
box.style.top = moveY + "px";
} else {
return;
}
}
document.onmouseup = function() {
isDrop = false; //设置为false不可移动
}
jwt基于base64进行加密
-
Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密
-
防范csrf攻击 防止token被截获之后进行跨站攻击的不安全性
- 用户使用用户名密码来请求服务器
- 服务器进行验证用户的信息
- 服务器通过验证发送给用户一个token
- 客户端存储token,并在每次请求时附送上这个token值
- 服务端验证token值,并返回数据
一个标准的json webtoken 包含三部分
头部 header 载荷playload 以及signature 签证
这个部分需要base64加密后的header和base64加密后的payload使用.
连接组成的字符串,然后通过header中声明的加密方式进行加盐secret
组合加密,然后就构成了jwt的第三部分
不需要再服务端进行会话信息的保存 json格式的通用性
promise 实现链式调用顺序加载三张图片
function loadImg(url) {
let img = new Image()
img.src = url
return new Promise((resolve, reject) => {
img.onload = () => {
console.log(url)
resolve()
}
img.onerror = (e) => {
reject(e)
}
})
}
loadImg(url1).then(() => {
return loadImg(url2)
}).then(() => {
return loadImg(url3)
})
http 报文格式
request 请求
请求行包括: 请求方法,URL(包括参数信息),协议版本这些信息(GET /admin_ui/rdx/core/images/close.png HTTP/1.1)
请求头部(Header)是一个个的key-value值,比如
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET4.0C; .NET4.0E)
空行(CR+LF):请求报文用空行表示header和请求数据的分隔
请求数据:GET方法没有携带数据, POST方法会携带一个body
Response报文
状态行包括:HTTP版本号,状态码和状态值组成。
响应头类似请求头,是一系列key-value值
Cache-Control: private
Content-Encoding: gzip
Server: BWS/1.1
Set-Cookie: delPer=0; path=/; domain=.baidu.com
空白行:同上,响应报文也用空白行来分隔header和数据
响应体:响应的data,本例中是一段HTML
js 动画和css动画的区别
- 代码的复杂度:js代码的复杂度高于css动画
- js由于代码的复杂度可能会因为线程的阻塞导致丢帧
- 控制:js谢谢的代码控制能力很强, 动画播放过程中对动画进行控制:开始、暂停、回放、终止、取消都是可以做到的 css 不能在半路反转动画,不能变换时间尺度,不能在特定的位置添加回调函数或是绑定回放事件,无进度报告
- css流畅度比较高
iframe可以解决加载换缓慢的第三方内容、并行加载脚本
缺点就是会阻塞主页面的onload时间,即使内容为空也需要加载时间
html5新增的语义化标签
section:在 web 页面应用中,该元素也可以用于区域的章节描述。
header:页面主体上的头部, header 元素往往在一对 body 元素中。
footer:页面的底部(页脚),通常会标出网站的相关信息。
nav:专门用于菜单导航、链接导航的元素,是 navigator 的缩写。
article:用于表现一篇文章的主体内容,一般为文字集中显示的区域。
级块性元素主要完成web页面区域的划分,确保内容的有效分割。
aside:用于表达注记、贴士、侧栏、摘要、插入的引用等作为补充主体的内容。
figure:是对多个元素进行组合并展示的元素,通常与 figcaption 联合使用。
code:表示一段代码块。
dialog:用于表达人与人之间的对话,该元素包含 dt 和 dd 这两个组合元素, dt 用于表示说话者,而 dd 用来表示说话内容。
行内语义性元素主要完成web页面具体内容的引用和描述,是丰富内容展示的基础。
meter:表示特定范围内的数值,可用于工资、数量、百分比等。
time:表示时间值。
progress:用来表示进度条,可通过对其 max 、 min 、 step 等属性进行控制,完成对进度的表示和监视。
video:视频元素,用于支持和实现视频文件的直接播放,支持缓冲预载和多种视频媒体格式。
audio:音频元素,用于支持和实现音频文件的直接播放,支持缓冲预载和多种音频媒体格式。
交互性元素主要用于功能性的内容表达,会有一定的内容和数据的关联,是各种事件的基础。
details:用来表示一段具体的内容,但是内容默认可能不显示,通过某种手段(如单击)与 legend 交互才会显示出来。
datagrid:用来控制客户端数据与显示,可以由动态脚本及时更新。
menu:主要用于交互菜单(曾被废弃又被重新启用的元素)。
command:用来处理命令按钮。
iframe 缺点
- iframe会阻塞主页面的onload时间
- 搜索引擎的检索程序无法解读这种页面 不利于seo
svg可任意的缩放图像的显示 但是不会破坏图像的清晰度、细节
文本独立 图像中的文字独立于图像
较小的文件
超强的显示效果、
超级颜色控制
获取url各个部分的方法
- window.location.host; //返回URL 的主机部分(带端口号),www.home.com:8080
window.location.hostname; //返回www.home.com:8080
window.location.href; //返回整个url字符串(在浏览器中就是完整的地址栏):http://www.home.com:8080/windows/location/page.html?ver=1.0&id=timlq#love
window.location.pathname; //返回URL 的路径部分(就是文件地址)/windows/location/page.html
window.location.protocol; //返回url 的协议部分 http:
window.location.port //url 的端口部分,如果采用默认的80端口,那么返回值并不是默认的80而是空字符 :返回 8080
设置是事件冒泡还是事件捕获
- 在addeventListener()的第三个参数(useCapture)设为true,就会在捕获阶段运行,默认是false冒泡
cookie和session实现保存用户登录 状态的机制
cookie(客户端的状态保存机制)
用户登录验证成功后,如果是使用 Cookie 记住登录状态,则客户端会将用户名等信息放在响应头的 Set-Cookie 属性中返回给服务器,之后的 HTTP 请求都会携带这个 Cookie ,实现记住登录。
session(服务端的状态保存机制)
用户登录验证成功后,如果是 session 的话,则服务器会将用户名等信息存放在本地,再随机生成一个登录标识通过 Cookie 返回给浏览器,之后浏览器每次发送请求也会携带这个 Cookie,服务器收到后便通过这个标识得到已登录的用户信息。
础。
details:用来表示一段具体的内容,但是内容默认可能不显示,通过某种手段(如单击)与 legend 交互才会显示出来。
datagrid:用来控制客户端数据与显示,可以由动态脚本及时更新。
menu:主要用于交互菜单(曾被废弃又被重新启用的元素)。
command:用来处理命令按钮。
iframe 缺点
- iframe会阻塞主页面的onload时间
- 搜索引擎的检索程序无法解读这种页面 不利于seo
svg可任意的缩放图像的显示 但是不会破坏图像的清晰度、细节
文本独立 图像中的文字独立于图像
较小的文件
超强的显示效果、
超级颜色控制
获取url各个部分的方法
- window.location.host; //返回URL 的主机部分(带端口号),www.home.com:8080
window.location.hostname; //返回www.home.com:8080
window.location.href; //返回整个url字符串(在浏览器中就是完整的地址栏):http://www.home.com:8080/windows/location/page.html?ver=1.0&id=timlq#love
window.location.pathname; //返回URL 的路径部分(就是文件地址)/windows/location/page.html
window.location.protocol; //返回url 的协议部分 http:
window.location.port //url 的端口部分,如果采用默认的80端口,那么返回值并不是默认的80而是空字符 :返回 8080
设置是事件冒泡还是事件捕获
- 在addeventListener()的第三个参数(useCapture)设为true,就会在捕获阶段运行,默认是false冒泡
cookie和session实现保存用户登录 状态的机制
cookie(客户端的状态保存机制)
用户登录验证成功后,如果是使用 Cookie 记住登录状态,则客户端会将用户名等信息放在响应头的 Set-Cookie 属性中返回给服务器,之后的 HTTP 请求都会携带这个 Cookie ,实现记住登录。
session(服务端的状态保存机制)
用户登录验证成功后,如果是 session 的话,则服务器会将用户名等信息存放在本地,再随机生成一个登录标识通过 Cookie 返回给浏览器,之后浏览器每次发送请求也会携带这个 Cookie,服务器收到后便通过这个标识得到已登录的用户信息。