前端面试题整合(有html、css、js、vue等)
#一、html
#行内外空元素
行内元素: a/img/span/b/strong/input/select/section
块级元素: div/p/table/ul/li/h1-h6
空元素: br/hr/img/input/link/meta
#浏览器内核
Trident: IE,360,搜狗
Gecko: Firefox
Presto: 旧Opera
Webkit: Safari,旧Chrome
Blink: Chrome,Opera
#浏览器存储
cookie: 一般表示用户状态的数据,大小为4KB,Cookies的数据始终在同源的http请求中携带,会在浏览器和服务器中来回传递。
sessionStorage:关闭浏览器后就销毁,大小一般都是:5MB,把数据存储在本地。
localStorage:永久保存,大小一般都是:5MB,把数据存储在本地。
#html新特性
加入了canvas绘图和SVG绘图,加入了video和audio标签。
语义化标签:header、nav、footer
本地存储:sessionStorage,sessionStorage
#html语义化
用正确的标签做正确的事情,html语义化让页面的内容结构更加简单易懂,
便于搜索引擎解析,便于阅读维护和理解。
#img的title和alt有什么区别?
title是当鼠标划到图片元素时显示的图片描述
alt是img的特有属性,是图片内容的等价描述,用于图片无法加载时显示
#Web标准,w3c标准是什么?
标签闭合、标签小写、不乱嵌套,使用外链css和js、结构行为表现的分离。
#二、css
#浏览器盒模型?
W3C: 宽度/padding/border/margin都是单独分开的
IE盒模型: 宽度 = 内容宽度+padding+border 是一起的
#清除浮动的方式
1.在子元素并级后面添加一个新元素,添加clear:both属性
2.给父元素添加overflow:hidden
3.通过给父级元素添加伪类after
.clearfix:after{
content:"";
display: block;
height:0;
clear:both;
visibility:hidden;
}
#CSS选择器
ID选择器 (#ID)
Class选择器 (.class名)
标签选择器 (标签)
通配符 (*)
相邻选择器 (div+p)
子选择器 (div>p)
后代选择器 (div p)
多个选择器 (div,p,a,ul)
伪类选择器 (a:hover)
#CSS样式优先级计算法
1/就近原则,后加样式优于前面的样式
2/内嵌样式>内联样式>外联样式
3/!Important 大于一切样式
#文本显示省略号
文本超出隐藏并显示省略号
overflow: hidden;
text-overflow:ellipsis; //文本超出显示省略
white-space: nowrap;
文本只显示两行,第二行超出隐藏并显示省略号
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box; //将对象作为弹性伸缩盒子模型显示
-webkit-line-clamp: 2; //用来限制在一个块元素显示的文本的行数
-webkit-box-orient: vertical; //设置或检索伸缩盒对象的子元素的排列方式
#宽高计算
width:calc(300px - 280px);
height: calc(100vh - 280px);
#flex布局
flex水平垂直居中
display: flex;
justify-content: center;
align-items: center;
align-content:flex-start (竖直方向对齐方式)
多个元素,竖直均匀分布
display: flex;
justify-content: space-around;
flex-direction: column;
左边固定宽度,右边占满剩余部分
.box{
width: 1200px;
height: 600px;
margin: 0 auto;
display: flex;
.left{
width: 200px;
height: 200px;
background-color: blue;
}
.rigth{
// width: 200px;
flex: 1;
height: 200px;
background-color: yellow;
}
}
#grid布局
居中
display: grid;
align-items: center;
justify-content: center;
导航目录自适应布局
每列宽度100px
,然后自动填充
display: grid;
justify-content: space-between;
grid-template-columns: repeat(auto-fill, 100rpx);
#水平垂直居中
position:absolute; //子元素
top: 0; bottom: 0; left: 0; right: 0;
margin: auto;
position:absolute; //子元素
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
#元素旋转
旋转45度
transform: rotate(45deg);
#响应式布局
1.媒体查询,@media可以根据不同的屏幕定义不同的样式。
// 如果浏览器窗口小于 500px, 背景将变为浅蓝色
@media only screen and (max-width: 500px) {
body {
background-color: blue;
}
}
2.百分比布局
2.使用rem布局,vue中使用amfe-flexible和postcss-px2rem插件完成。
原生
// 设置rem
function watchWindowSize() {
// 设置字体大小 1px=0.01rem
var w = document.documentElement.clientWidth;
var h = document.documentElement.clientHeight;
console.log(w, h)
document.documentElement.style.fontSize = w / 19.2 + 'px';
}
// 将事件侦听器函数附加到窗口的resize事件
window.addEventListener("resize", watchWindowSize);
// 调用该函数
watchWindowSize();
#BFC
BFC即 Block Formatting Contexts ,块级格式化上下文
独立的渲染区域,内部元素的渲染不会影响外界。
形成BFC 条件
浮动元素 float属性不为none
定位---position: absolute,fixed
给元素添加display属性---display: inline-block, flex, inline-flex, table-cell,table-caption; 给元素添加overflow属性----overflow: hidden,auto,scroll(除了visible);
#三、js
#字符串方法
String charAt 返回在指定位置的字符。 charCodeAt 返回在指定的位置的字符的 Unicode 编码。 IndexOf 返回某个指定的字符串值在字符串中首次出现的位置。 slice 提取字符串的片断,并在新的字符串中返回被提取的部分。 split 把字符串分割为字符串数组。 toLowerCase 把字符串转换为小写。 toUpperCase 把字符串转换为大写。 trim 去除字符串两边的空白
模板字符串
let name = '张三'
let str1 = `名字${name}`
#数组方法
-
join()
数组转字符串,参数为分隔符。返回字符串,原数组不变。
-
push()和pop()
向数组的末尾添加元素,返回数组长度,原数组改变。
删除数组的末尾元素,返回删除的元素,原数组改变
-
shift() 和 unshift()
删除数组的第一个元素,返回删除元素,原数组改变。
向数组的开头增加元素,返回数组长度,原数组改变。
-
sort()
对数组的元素进行排序,默认按照字符编码排序,参数为函数。返回新数组,原数组改变。
let arr1 = arr.sort(function (a, b) { return a - b }) // 升序排序
-
reverse() 反转数组的元素顺序。返回新数组,原数组改变。
-
concat() 合并数组,返回新数组,原数组不变。
-
slice() 数组截取
arrayObject.slice(start,end),返回所选范围的元素的数组,原数组不变。
// let arr1 = arr.slice(1,3) //从索引为1开始到索引为3之前结束 // let arr1 = arr.slice(2) //从索引为2开始全部 // let arr1 = arr.slice(-1) // 从末尾元素开始选
-
splice() 删除或新增
arrayObject.splice(index,howmany,item1,.....,itemX)
从数组中添加或删除元素,返回被删除的元素数组,原数组改变
let arr1 = arr.splice(1, 2, 'new') //从索引为1开始删除两个元素,并在该位置添加元素
-
indexOf()和 lastIndexOf()
返回参数在数组中的位置,原数组不变。
返回参数在数组中最后出现的位置,原数组不变。
-
includes() 判断一个数组是否包含一个指定的值。返回布尔值,原数组不变。
-
find()和findIndex()
返回数组中符合条件的第一个元素,参数为函数,原数组不变。
let arr1 = arr.find(function (e) { return e > 2 })
返回数组中符合条件的第一个元素的索引。
-
flat() 多维数组转一维数组,返回新数组,原数组不变。
-
forEach() 和map()
遍历数组,forEach没有返回,map返回新数组。
// arr.forEach(e, i, arr => { // console.log(e, i, arr) // }); let arr1 = arr.map(e, i, arr => { return e = e + 1 })
-
filter() 返回数组中符合条件的全部元素,参数为函数,原数组不变。
let arr1 = arr.filter((e) => { return e > 3 })
-
every() 和 some()
every()是对数组中每一项运行给定函数,如果该函数对每一项返回true,则返回true。
some()是对数组中每一项运行给定函数,如果该函数对任一项返回true,则返回true。
#数组去重
// 数组去重
let arr = [9,8,5,4,3,1,2,8,6,5,6,4,8,2,3,4,8,4]
function fun1(arr){
return [...new Set(arr)]
}
function fun2(arr){
let tmp = []
arr.forEach(e => {
if(tmp.indexOf(e)==-1){
tmp.push(e)
}
});
return tmp
}
#数组排序
// 数组排序
let arr = [9, 8, 5, 4, 3, 1, 2, 6]
function fun1(arr) {
return arr.sort((a, b) => {
return a - b
})
}
#Date时间对象
getFullYear 从 Date 对象以四位数字返回年份。 getMonth 从 Date 对象返回月份 (0 ~ 11)。 getDate 从 Date 对象返回一个月中的某一天 (1 ~ 31)。 getHours 返回 Date 对象的小时 (0 ~ 23)。 getMinutes 返回 Date 对象的分钟 (0 ~ 59)。 getSeconds 返回 Date 对象的秒数 (0 ~ 59)。 getDay 从 Date 对象返回一周中的某一天 (0 ~ 6)。 getTime 返回 1970 年 1 月 1 日至今的毫秒数。
let time = new Date()
let year = time.getFullYear()
let mon = time.getMonth() + 1
let day = time.getDate()
let hou = time.getHours()
let min = time.getMinutes()
let timeStr = time.getTime()
console.log(time)
console.log(year, mon, day, hou, min)
console.log(timeStr)
#数据类型
1.基本数据类型(栈):Number,String,Boolean,Undefined,Null,Symbol(es6)
2.引用数据类型(堆):Object,Array,Function , Date
JavaScript 里使用 typeof 来判断数据类型,只能区分基本类型
// 判断数据类型 Object.prototype.toString.call()
console.log(Object.prototype.toString.call('1')) //[object String]
console.log(Object.prototype.toString.call(true)) //[object Boolean]
console.log(Object.prototype.toString.call([])) //[object Array]
console.log(Object.prototype.toString.call({})) //[object Object]
#new操作符在创建实例的经历的阶段
new创建了一个对象,共经历了4个阶段:
1.创建一个空对象
2.设置原型链
3.让实例化对象中的this指向对象,并执行函数体
4.返回创建的对象
#闭包
函数内部嵌套的函数
有权访问另一个函数作用域中的变量的函数。常见方式,就是在一个函数内部创建另一个函数。
功能:在函数外,访问函数内的变量。保持引用,不被回收。创建私有环境。
缺点:内存泄漏
function fn() {
let a = 11
return function () {
console.log(a)
}
}
console.log(fn())
let fn1 = fn()
fn1()
#原型
1.每一个函数都有一个'prototype'属性,即显示原型。prototype(对象属性)的所有属性和方法,都会被构造函数的实例继承。
2.每一个实例对象都有一个'proto '属性,即隐式原型。
原型链
获取对象属性时,如果对象本身没有这个属性,就会去找这个对象'proto '属性指向上一个对象,一直找到最顶层(Object.prototype
)为止。Object.prototype对象也有proto属性值为null
// 原型
// 获取原型的方法
// 1.对象的 '__proto__'
// 2.构造函数的prototype
// let cat = {
// name: '喵喵'
// }
// cat.__proto__.eat = function () {
// console.log('吃鱼')
// }
// cat.eat()
// function Cat(name, age) {
// this.name = name
// this.age = age
// }
// let cat = new Cat('喵喵', 2)
// Cat.prototype.eat = function () {
// console.log('吃鱼')
// }
// console.log(cat)
// cat.eat()
#深拷贝
// 深拷贝浅拷贝
// Object.assign() 对象只有一层时是深拷贝
// let obj = {
// name: '张三',
// age: 18
// }
// let obj1 = Object.assign({}, obj)
// obj.age = 20
// console.log(obj)
// console.log(obj1)
// JSON.stringify 和 JSON.parse 实现深拷贝,但不能拷贝对象中的方法
// let obj = {
// name: '张三',
// age: 18,
// like: {
// a: 11,
// b: 22
// }
// }
// let str = JSON.stringify(obj)
// let obj1 = JSON.parse(str)
// obj.like.a = 10
// console.log(obj)
// console.log(obj1)
// 递归实现深拷贝
let obj = {
name: '张三',
age: 18,
like: {
a: 11,
b: 22
},
arr: [1, 2, 3, 4]
}
function copy(obj) {
let newObj = obj.constructor === Array ? [] : {};
for (let i in obj) {
if (obj[i] instanceof(Object || Array)) {
newObj[i] = copy(obj[i])
} else {
newObj[i] = obj[i]
}
}
return newObj
}
let obj1 = copy(obj)
obj.age = 20
obj.like.a = 15
obj.arr.push(5)
console.log(obj)
console.log(obj1)
#ES6
1.let 和const
var定义变量,会有变量声名提升,let不会。
var定义全局的变量,let和const定义块级的变量。
const定义常量。for循环用let。
2.模板字符串
// 模板字符串
let box = document.getElementById('box')
let name = '张三'
let age = '18'
let str = "<ul><li>" + name + "</li></ul>"
let str1 = `<ul><li>${name}</li></ul>`
box.innerHTML = str1
3..函数默认值
// 函数默认值
function add(a = 10, b = 20) {
return a + b
}
console.log(add()) //30
函数剩余参数
// 剩余参数 将多个参数合并为一个数组
function fn(...arg) {
console.log(arg)
}
fn(1, 2, 3, 4, 5, 6)
4.拓展运算符
// 拓展运算符 将数组分离为多项参数
console.log(Math.max(1, 2, 3))
let arr = [1, 2, 3, 4, 6, 8, 4, 9, 7]
console.log(Math.max(...arr))
5.箭头函数
// 箭头函数
let fn = (a, b) => a + b
console.log(fn(1, 2))
箭头函数没有this指向
箭头函数不能使用new来实例化对象
this指向:
1.普通函数,this指向window
2.谁调用指向谁
3.call、apply、bind这三个方法将this指向绑定在传入的对象上
4.new实例化后指向实例对象
5.箭头函数 ,根据外层作用域来决定this
call,apply,bind的区别?
call和apply改变this指向,bind则是绑定this指向后返回新函数。
call和apply立即执行,bind需要调用才执行。
call如果传的多个参数,依次填,apply则是第二个参数是数组。
let boy = {
name: '小小',
fn() {
console.log(this.name)
},
like(a, b) {
console.log('喜欢' + a + '和' + b)
}
}
let man = {
name: '王大',
}
boy.fn()
boy.fn.call(man)
boy.like.call(man, '吃饭', '唱歌')
boy.like.apply(man, ['睡觉', '玩'])
let fn1 = boy.like.bind(man, '吃饭1', '唱歌1')
6.解构赋值
// 解构赋值 赋值运算符的拓展
let man = {
name: '张三',
age: 18
}
let {
name,
age
} = man
console.log(name, age)
let arr = [1, 2, 3]
let [a, b, c] = arr
console.log(a, b, c)
7.对象的方法
// 对象的方法
// 1.'is()' 等价于 '===' 比较两个值相等否
console.log(Object.is(NaN, NaN))
// 2. assign() 对象的合并
// Object.assign(obj, obj1, obj2) obj为目标对象
let obj = {}
let obj1 = {
name: '张三'
}
let obj2 = {
age: 18
}
Object.assign(obj, obj1, obj2)
console.log(obj)
console.log(obj1)
console.log(obj2)
8.set和map
// Set Set允许你存储任何类型的唯一值,无论是原始值或者是对象引用。
let arr = [1, 2, 2, 3, 5, 5, 6, 6, 7, 7, 7, 8]
let set = new Set(arr)
set.add(10)
set.delete(8)
console.log(set.has(10))
console.log(set)
let arr1 = [...set]
console.log(arr1)
// Set 是无重复值的有序列表,有点像数组。
// Map 是有序的键值对,其中的键允许是任何类型,有点像对象。
let map = new Map()
map.set('name', '张三')
console.log(map)
#Promise
Promise 是异步编程的一种解决方案
Promise
对象是一个构造函数,用来生成Promise
实例
// promise
let pro = new Promise((res, rej) => {
let man = {
name: '张三',
age: '18'
}
res(man)
})
pro.then(res => {
// console.log(res)
})
// console.log(pro)
let pro1 = new Promise((res, rej) => {
res(1)
})
// console.log(pro1)
async function getdata() {
let a = await pro1
console.log(a)
}
getdata()
问执行顺序,控制台依次打印?
fun() {
const promise1 = new Promise((resolve, reject) => {
console.log('3')
resolve('4')
})
console.log('1')
setTimeout(function() {
console.log('2')
}, 0);
promise1.then(res => {
console.log(res)
})
console.log('5')
}
// 31542
10.class类
// es6 类与继承
class Cat {
constructor(name, age) {
this.name = name;
this.age = age
}
}
let cat = new Cat('大喵', 3)
Cat.prototype.like = function () {
console.log('猫喜欢睡觉')
}
cat.like()
class Dog extends Cat {
wang() {
console.log('旺旺')
}
}
let wc = new Dog('旺财',4)
console.log(wc)
wc.wang()
// 原型的继承
//有 A,B两个类,B要继承A,让B的prototype = A 的实例
B.prototype = new A()
#http的状态码
1XX:信息状态码
2XX:成功状态码
3XX:重定向
4XX:客户端错误
5XX:服务器错误
常见状态码:
304 自从上次请求后,请求的网页未修改过。
401 没有权限,请求要求身份验证。
403 服务器已经理解请求,但是拒绝执行它。
404 请求失败
500 服务器遇到一个未曾预料的情况,导致无法完成对请求的处理
503 由于请示服务器维护或者过载,服务器当前无法处理请求
#get与post的区别
GET在浏览器回退时是无害的,而POST会再次提交请求
GET产生的URL地址可被Bookmark,而POST不可以
GET请求会被浏览器主动cache缓存,而POST不会,除非手动设置
GET请求只能进行url编码,而POST支持多种编码方式。
GET请求参数会被完整的保留在浏览器历史记录中,而POST中的参数不会被保留
GET请求在URL中传送的参数是有长度限制的,而POST没有
对参数的数据类型,GET只接受ASCII字符,而POST没有限制
GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息
GET参数通过URL传递,POST放在Request body中
#ajax的过程
// 1.创建xhr对象
var xhr = new XMLHttpRequest()
// 2.设置请求方式
xhr.open('method', URL, async);
// 3.设置回调函数
xhr.onreadystatechange = () => {
if (xhr.readyState !== 4) return
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
console.log(111)
} else {
console.log(000)
}
}
// 4.发送请求
xhr.send()
// 5.结果处理
#axios封装
// 创建axios实例
var instance = axios.create({ timeout: 1000 * 12});
// 设置post请求头
instance.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
/**
* 请求拦截器
* 每次请求前,如果存在token则在请求头中携带token
*/
instance.interceptors.request.use(
config => {
// 登录流程控制中,根据本地是否存在token判断用户的登录情况
// 但是即使token存在,也有可能token是过期的,所以在每次的请求头中携带token
// 后台根据携带的token判断用户的登录情况,并返回给我们对应的状态码
// 而后我们可以在响应拦截器中,根据状态码进行一些统一的操作。
const token = store.state.token;
token && (config.headers.Authorization = token);
return config;
},
error => Promise.error(error))
// 响应拦截器
instance.interceptors.response.use(
// 请求成功
res => res.status === 200 ? Promise.resolve(res) : Promise.reject(res),
// 请求失败
error => {
const { response } = error;
if (response) {
// 请求已发出,但是不在2xx的范围
errorHandle(response.status, response.data.message);
return Promise.reject(response);
} else {
// 处理断网的情况
// eg:请求超时或断网时,更新state的network状态
// network状态在app.vue中控制着一个全局的断网提示组件的显示隐藏
// 关于断网组件中的刷新重新获取数据,会在断网组件中说明
if (!window.navigator.onLine) {
store.commit('changeNetwork', false);
} else {
return Promise.reject(error);
}
}
});
export default instance;
#四、vue
#vue的指令
v-text:把数据插入标签
v-html:把html插入标签
v-if:判断是否为真,然后重组、销毁DOM节点
v-for:数据循环
v-bind:class 绑定一个属性
v-model:实现双向绑定
v-on:添加事件
v-else:配合v-if使用
#v-show和v-if
v-show指令是通过修改元素的display的CSS属性让其显示或隐藏
v-if指令是直接销毁和重建DOM节点,达到让元素显示和隐藏的效果
#CSS只在当前组件中生效
在当前文档中使用style标签,并添加scope属性
#动态类绑定
<div class="color1" :class="{'color2':showBtn}">
// showBtn: false,
<div :class="['color1', activeStatus ? 'color2' : '']">
// activeStatus:true,
#避免 v-if 和 v-for
v-for 比 v-if 具有更高的优先级,每一次都需要遍历整个数组,造成不必要的计算,影响性能。
永远不要把 v-if 和 v-for 同时用在同一个元素上,带来性能方面的浪费(每次渲染都会先循环再进行条件判断)
避免出现这种情况,则在外层嵌套template(页面渲染不生成dom节点),在这一层进行v-if判断,然后在内部进行v-for循环
#虚拟Dom
用JS模拟真实的dom结构,作用是高效的渲染页面 减少不必要的dom操作 提高渲染效率
#双向绑定
Vue是采用数据劫持+”发布-订阅模式“的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
<body>
<h1>双向数据绑定</h1>
<input type="text" id="name">
<div>显示:<span id="name1"></span></div>
</body>
<script>
let obj = {}
let input = document.getElementById('name')
input.oninput = ((e) => {
obj.name = e.target.value
})
Object.defineProperty(obj, 'name', {
get: () => {},
set: (e) => {
// console.log(e)
// obj.name = e
document.getElementById('name1').innerText = e
}
})
</script>
#dota是函数?
组件中的data
写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的data
,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。
#$nextTick
在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM
#父子组件传值
父传子
<div>父级</div>
<son :obj2="obj1"></son>
import son from "../components/son.vue";
export default {
data() {
return {obj1: {name: "张三",age: 18}};
},
components: { son }
...
<div>这是子组件</div>
<div>{{ obj2.name }},{{ obj2.age }}</div>
export default {
props: {
obj2: Object,
}
...}
子传父
父页面
<son1 @sonEvent="faEvent"></son1>
methods: {
faEvent(e) {
console.log(e);
},
},
子页面
<button @click="send">发送</button>
data() {return { obj: {name: "小王",age: 20,}, };},
methods: {
send() {
this.$emit("sonEvent", this.obj);
},
},
#watch
基础用法
export default {
name: 'HelloWorld',
data () {
return {
name: '',
watchName:''
}
},
watch: {
name (val) {
this.watchName = val;
}
}
}
deep 深度监听
data () {
return {
person: {
id: 1,
name: '沐'
}
}
}
watch: {
person: {
handler (val) {
console.log('深度监听:', val);
},
deep: true
}
}
#Vue Router
标签中使用
<router-link :to="{ path: 'test', query: { a: 10 } }">跳转</router-link>
<router-view></router-view>
方法中使用
this.$router.push({ path: "test", query: { aa: 100 } });
// 取值
this.$route.query
嵌套路由
const routes = [
{
path: '/user/:id',
component: User,
children: [
{
path: 'profile',
component: UserProfile,
}
],
},
]
// 路径中有 :id 为动态路由,this.$route.params获取id
重定向
const routes = [{ path: '/home', redirect: '/' }]
#路由守卫
全局前置守卫 router.beforeEach
//to:将要进入的路由 from:正要离开的路由
router.beforeEach((to, from, next) => {
if ('有token') {
next()
} else {
to.path('去登录页')
}
})
全局后置钩子 router.afterEach
router.afterEach((to, from) => {...})
路由独享的守卫 beforeEnter
const routes = [
{
path: '/users/:id',
component: UserDetails,
beforeEnter: (to, from) => {
// reject the navigation
return false
},
},
]
组件内的守卫
beforeRouteEnter
beforeRouteUpdate
beforeRouteLeave
路由修改网页标题
router.beforeEach((to,from,next) => {
if(to.meta.title) {
document.title = to.meta.title; //在路由里面写入的meta里面的title字段
}
next();
})
#路由模式
hash模式
使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载,其显示的网路路径中会有 “#” 号,有一点点丑。这是最安全的模式,因为他兼容所有的浏览器和服务器。
history模式 美化后的hash模式,会去掉路径中的 “#”。依赖于Html5 的history,pushState API,所以要担心IE9以及一下的版本,感觉不用担心。并且还包括forward、back、go三个方法,对应浏览器的前进,后退,跳转操作。就是浏览器左上角的前进、后退等按钮进行的操作。
#vuex
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
user: {
name: '',
age: null
}
},
// 获取数据,类似计算属性
getters: {
getUser(state) {
return state.user
}
},
mutations: {
// 修改数据user
updataUser(state, user) {
state.user = user
}
},
// actions为异步操作
actions: {
asyncUpdataUser(context, user) {
setTimeout(() => {
context.commit('updataUser', user)
}, 2000);
}
},
// Vuex 允许我们将 store 分割成模块
// 每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块
modules: {
}
})
console.log(this.$store.getters.getUser);
this.$store.commit("updataUser", this.user);
this.$store.dispatch("asyncUpdataUser", this.user);
#vue性能优化
路由懒加载,访问时才异步加载,import()实现异步组件
组件缓存keep-alive,缓存组件以及状态
v-show复用dom,避免重复创建组件
v-for 遍历时不使用v-if
事件销毁,组件卸载的时候,销毁一些自定义的事件,如定时器
图片懒加载 vue-lazyload
按需加载第三方组件库
服务器端开启gzip压缩
#使用echarts
<div ref="echarBox" class="echart-box" style="height: 420px"></div>
import * as echarts from "echarts";
export default {
data() {
return {};
},
components: {},
mounted() {
this.drawChart();
},
created() {},
methods: {
drawChart() {
this.chart = echarts.init(this.$refs.echarBox);
const option = {};
this.chart.setOption(option);
},
},
};
#跨域解决
1.让服务器的请求头设置允许跨域。
2.jsonp实现跨域请求。
3.vue配置跨域
根目录vue.config.js
module.exports = {
devServer: {
proxy: { //配置跨域
'/api': {
target: 'https://jsonplaceholder.typicode.com/', //接口地址
changOrigin: true, //允许跨域
pathRewrite: {
'^/api': ''
}
},
}
},
};
#环境配置
根目录新建
.env.development,测试环境
# development
VUE_APP_BASE_API = 'https://api.development.xxx.com'
NODE_ENV = 'development'
.env.production,正式环境
# production
VUE_APP_BASE_API = 'https://api.production.xxx.com'
NODE_ENV = 'production'
#判断移动、pc端
_isMobile() {
let flag = navigator.userAgent.match(
/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i
);
if (flag) {
this.isMobile = true;
} else {
this.isMobile = false;
}
// console.log(this.isMobile);
},
#五、webpack
#安装
npm init -y 生成package.json文件
npm i webpack webpack-cli --save-dev
#六、小程序
#1.生命周期
页面生命周期
onLoad、onShow、onReady、onHide、onUnload
#、nodejs
#、其他
#节流和防抖
节流和防抖本质上都是控制事件执行的频率,但是触发事件的时机本质上有区别,防抖是在用户多次触发事件,当用户停止触发事件,将事件执行一次;节流是用户多次触发事件,会在多次触发的过程中,间隔执行事件。
防抖是最后一个执行事件才会触发函数,节流在一定时间内会触发函数。
防抖案例:按钮一直被点击,控制时间1s内被点击,事件不执行,1s后没有被点击则执行事件。
节流案例:按钮被点击后变为禁用状态,5s后变为可点击状态。
防抖:输入框应用
节流:页面滚动加载数据
// 防抖
// @fn 是对应请求数据
// @ms 是用户多次触发事件的时间间隔 是一个毫秒数
function debounce(fn, ms) {
let timeout = null
return function() {
clearTimeout(timeout)
timeout = setTimeout(() => {
fn.apply(this, arguments)
}, ms)
}
}
//节流
// @fn 是对应请求数据
// @ms 是用户多次触发事件的时间间隔 是一个毫秒数
function throttle(fn, ms){
let flag = true
return function(){
if(!flag) return
flag = false
setTimeout(()=>{
fn.apply(this, arguments)
flag = true
}, ms)
}
}
#、websocket
#简介
-
什么是 WebSocket websocket是HTML5开始提供的一种网络通信协议,它的目的是在浏览器之间建立一个不受限的双方通信的通道,比如说,服务器可以在任意时刻发送信息给浏览器。在websocket的API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输
-
WebSocket 的方法 ws.send() - 向服务器发送数据 ws.close() - 关闭连接
-
WebSocket 的事件 ws.onopen - 建立连接时触发 ws.onmessage - 客户端接受服务端数据时触发 ws.onerror - 通信错误时触发 ws.onclose - 连接关闭时触发
-
WebSocket.readyState readyState 属性返回实例对象的当前状态,共有四种状态 0 - 表示正在连接 1 - 表示连接成功,可以进行通信 2 - 表示连接正在关闭 3 - 表示连接已经关闭,或者打开连接失败 使用
// 创建一个WebSocket对象 var ws = new WebSocket("接口地址") // 连接成功时触发 ws.onopen = function() { alert("连接成功") } // 连接失败时触发 ws.onerror = function() { alert("连接失败") } // 发送数据 ws.send(); // 向服务端发送请求 // 接收消息时触发 ws.onmessage = function(MessagEvent) { console.log(MessagEvent.data) } // 连接关闭的回调函数 ws.onclose = function(){ alert("close") }
#地图map
https://lbsyun.baidu.com/index.php?title=jspopular3.0/guide/helloworld(opens new window)