前端面试题整合(有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

#、其他

#节流和防抖

https://blog.csdn.net/m0_46846526/article/details/117890111?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2~default~LandingCtr~Rate-1.queryctrv4&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~LandingCtr~Rate-1.queryctrv4&utm_relevant_index=2(opens new window)

节流和防抖本质上都是控制事件执行的频率,但是触发事件的时机本质上有区别,防抖是在用户多次触发事件,当用户停止触发事件,将事件执行一次;节流是用户多次触发事件,会在多次触发的过程中,间隔执行事件。

防抖是最后一个执行事件才会触发函数,节流在一定时间内会触发函数。

防抖案例:按钮一直被点击,控制时间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)