前端高频面试题总结(看完这些面试轻轻松松)

cookies、sessionStorage和localStorage区别


分析:考察求职者对于本地存储的方式是否熟悉,因为初学者会把 cookies 和 sessionStorage 与localStorage 搞混

解答:

cookies:它是网站用来标记用户身份的一段数据,通常情况下是一段加密的字符串,并且默认情况之下只会在同源的 HTTP 请求中携带

sessionStorage:它是浏览器本地存储的一种方式,以键值对的形式进行存储,并且存储的数据会在浏览器关闭之后自动删除

localStorage:它也是浏览器本地存储的一种方式,和 sessionStorage 一样,也是以键值对的形式存在的,不过它存储的是一个持久化的数据,一般不主动删除,数据会一直存在

display:none;与visibility:hidden;opacity:0;


分析:这是一个比较容易出现错误的 CSS 问题,没有大量实际开发经验的开发者,很难了解它们之间的区别

解答:

共同点:它们都可以让元素不可见

不点:

display:none; 会让元素完全从染树中消失,不染的时候不占据任何空间。而 visibility.hidden; 不会让元素从染树消失,不染时元素继续占据空间,只是内容不可见display: none;是非继承属性,子孙节点消失是因为元素从渲染树消失造成,通过修改子孙节点属性无法显示;而visibility: hidden;是继承属性,子孙节点消失由于继承了 hidden,通过设置visibility: visible;可以让子孙节点显式

opacity:0,该元素隐藏起来了,但不会改变页面布局,

并且,如果该元素已经绑定一些事件,如click事件,

那么点击该区域,也能触发点击事件的

visibility:hidden,该元素隐藏起来了,

但不会改变页面布局,但是不会触发该元素已经绑定的事件

display=none,把元素隐藏起来,并且会改变页面布局,

可以理解成在页面中把该元素删除掉一样

为什么要初始化CSS样式


问题: 什么是 postcss,以及 postcss 有什么作用?

分析:有很多已经工作了两年、三年的开发者依然无法解释清楚 postcss 是什么,以及它的作用。

解答:

·首先明确 postcss 是一个平台

·基于这个平台,可以使用一些插件,来优化 css 的代码。比如说: autoprefixer 插件,他就需要基于 postcss 使用,作用是可以帮助我们为 css 增加上不同的浏览器前

闭包


分析:闭包的问题一直是在前端方面非常被关注的问题,这个问题作为面试题经久不衰

解答:

什么是闭包?

闭包就是能够读取其他函数内部变量的一一个通常情况下,我们会在一个函数中,去创建另外一个函数然后通过新创建的这个函数来访问上层函数的局部变量,被访问到的局部变量会始终保存在内存之中

前端高频面试题总结(看完这些面试轻轻松松)_第1张图片

原型与原型链


前端高频面试题总结(看完这些面试轻轻松松)_第2张图片

null、undefined


前端高频面试题总结(看完这些面试轻轻松松)_第3张图片

KeepAlive


前端高频面试题总结(看完这些面试轻轻松松)_第4张图片
前端高频面试题总结(看完这些面试轻轻松松)_第5张图片

同步和异步


前端高频面试题总结(看完这些面试轻轻松松)_第6张图片

路由VueRouter两种模式hash和history


前端高频面试题总结(看完这些面试轻轻松松)_第7张图片

vue中传递参数


前端高频面试题总结(看完这些面试轻轻松松)_第8张图片

vue双向绑定原理


前端高频面试题总结(看完这些面试轻轻松松)_第9张图片

vue生命周期


前端高频面试题总结(看完这些面试轻轻松松)_第10张图片

typeof与instanceof


前端高频面试题总结(看完这些面试轻轻松松)_第11张图片

bind、call、apply


前端高频面试题总结(看完这些面试轻轻松松)_第12张图片

event loop(事件循环)


前端高频面试题总结(看完这些面试轻轻松松)_第13张图片

promise


webpack


前端高频面试题总结(看完这些面试轻轻松松)_第14张图片

this对象


前端高频面试题总结(看完这些面试轻轻松松)_第15张图片

js数据类型


  1. 基本数据类型

  1. Number、String、Boolean、Null、Undefined、Symbol、bigInt

  1. 引用数据类型

  1. object、Array、Date、Function、RegExp

== 和 ===的区别


  1. ==是非严格意义上的相等

  1. 值相等就相等

  1. ===是严格意义上的相等,会比较两边的数据类型和值大小

  1. 值和引用地址都相等才相等

js数组和对象的遍历方式


  1. for in

  1. for

  1. forEach

  1. for-of

map与forEach的区别


  1. forEach 方法,是最基本的方法,就是遍历与循环,默认有 3 个传参:分别是遍历的数组内

容 item、数组索引 index、和当前遍历数组 Array

  1. map 方法,基本用法与 forEach 一致,但是不同的,它会返回一个新的数组,所以 callback

需要有 return 值,如果没有,会返回 undefined

箭头函数与普通函数的区别?


  1. 函数体内的 this 对象,就是定义时所在的对象,而不是使用时所在的对象

  1. 不可以当作构造函数,也就是说,不可以使用 new 命令,否则会抛出一个错误

  1. 不可以使用 arguments 对象,该对象在函数体内不存在。如果要用,可以用 Rest 参数代替

  1. 不可以使用 yield 命令,因此箭头函数不能用作 Generator 函数

同源策略


同源指的是域名、协议、端口号相同

如何解决跨域


  1. jsonp跨域

  1. document.domain + iframe 跨域

  1. nodejs中间件代理跨域

  1. 后端在头部信息里面设置安全域名

前端高频面试题总结(看完这些面试轻轻松松)_第16张图片

attribute 和 property 的区别是什么?


  1. attribute 是 dom 元素在文档中作为 html 标签拥有的属性

  1. property 就是 dom 元素在 js 中作为对象拥有的属性。

  1. 对于 html 的标准属性来说,attribute 和 property 是同步的,是会自动更新的

  1. 但是对于自定义的属性来说,他们是不同步的

script 引入方式?


  1. html 静态

    JSONP的实现

    下面我会对JSONP做一个最基本的实现。使用Vue和node.js分别实现客户端和服务端,代码地址。

    首先我们先看客户端的实现:

    //获取header的第一个子元素 let container = document.getElementsByTagName("head")[0]; /** * 生成随机字符串 */ function makeid() { var text = ""; var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; for (var i = 0; i < 5; i++) text += possible.charAt(Math.floor(Math.random() * possible.length)); return text; } /** * jsonp请求的实现。返回一个promise对象对应请求成功和请求失败。 * @param {*请求的url} url * @param {*请求的参数} options */ function jsonpRequest(url, options) { return new Promise((resolve, reject) => { try { if (!url) { reject({ err: new Error("url不能为空"), result: null }); } if (!document || !global) { reject({ err: new Error("系统环境有问题"), result: null }); } //创建一个script元素 let scriptNode = document.createElement("script"); //请求参数 let data = options || {}; //回调函数的具体值,服务器和客户端就根据这个方法名来确定请求与返回数据之间的对应。 let fnName = "jsonp" + makeid(); // 把callback加入请求参数中 data["callback"] = fnName; // 拼接url var params = []; //参数的拼接与处理 for (let [key, value] of Object.entries(data)) { params.push(encodeURIComponent(key) + "=" + encodeURIComponent(data[key])); } url = (url.indexOf("?")) > 0 ? (url + "&") : (url + "?"); url += params.join("&"); //把处理好的url赋值给script元素的src属性。 scriptNode.src = url; // 把回调函数暴露为全局方法。script加载回来以后,会执行fnName对应的这个方法。 global[fnName] = function(ret) { resolve({ err: null, result: ret }) //请求完成。删除script元素 container.removeChild(scriptNode); //全局对象中删除已经请求完成的回调方法 delete global[fnName]; } // script元素遇到错误 scriptNode.onerror = function(err) { reject({ err: err, result: null }) //删除script元素和全局回调方法 container.removeChild(scriptNode); global[fnName] && delete global[fnName]; } //指定元素类型 scriptNode.type = "text/javascript"; //把script元素添加到header元素中。到这里script元素就会自动加载src。也就是我们的请求发出去了。 container.appendChild(scriptNode) } catch (error) { //异常处理捕获 reject({ err: error, result: null }); } }); } export default jsonpRequest;

    这段代码主要做了如下几件事:

    • 创建一个script标签元素,并且添加到header元素里面。

    • 拼接script元素的src属性,其中必然好汉callback这个参数,服务端根据这个参数的值回调。

    • 回调以后需要手动把script标签元素移除,并且删除全局的回调函数名。

    客户端的使用如下,是不是感觉简洁明了,比ES5的回调爽多了:

    import jsonpRequest from "../lib/jsonpRequest.js"; async sendJSONPRequest() { //参数 let params = { name: "老黄", site: "www.huangchengdu.com" }; this.showLoading(); //发送请求 let { err, result } = await jsonpRequest( "https://www.huangchengdu.com/jsonp/jsonpRequest", params ); //处理返回的数据 this.hiddenLoading(); if (err) { alert(err.message || "请求出错了"); this.serverData.err = JSON.stringify(err); } else { this.serverData = result; } }

    服务端的实现如下。

    let express = require('express'); let router = express.Router(); //JSONP请求 router.get('/jsonpRequest', function(req, res, next) { //console.log("=====================" + JSON.stringify(req.query)); //获取name和site参数的值 let name = req.query.name; let site = req.query.site; //拼接回调值 let serverres = { serverReceive:{ name:name, site:site }, serverSend:"hello," + name + ".your site is https://" + site } //返回值。其实就是callback....()种种类型javascript字符串 res.end(req.query.callback + "(" + JSON.stringify(serverres) + ")") }); module.exports = router;

    服务端代码说明如下:

    • res.end是express表示对http请求返回。具体返回的数据类似于callback随机数(服务端数据)这种类型。

    • 客户端在收到callback随机数(服务端数据)这个数据以后,会自动按照javascript脚本解析执行。具体就是一个全局方法调用,方法名是callback随机数,参数是服务端数据。这样就实现了服务端数据的回调。

    • 客户端在global对象下面注册了callback随机数这个方法。具体代码是上面global[fnName] = function(ret) {这一行。

    • callback随机数是服务端和客户端商量,具体可以自己决定,真实的时候类似于callbacksuijishu这种类型。

    JSONP请求报文

    JSONP本质上就是一个普通的GET请求。无非就是这个请求是通过script标签来发送的。而且请求参数里面必定会有一个callback参数。

    下面我们具体抓包看一下我们的请求报文:

    GET /jsonp/jsonpRequest?name=%E8%80%81%E9%BB%84&site=www.huangchengdu.com&callback=jsonpiFuL4 HTTP/1.1 Host: www.huangchengdu.com Accept: */* Connection: keep-alive Cookie: session=s%3Anot8KTW5FiTLY0VNgrrKksXY96AE2kWT.hrQeyL%2BVjt8ICJjfFqoFdV8JV3lx0IsDntx%2B%2Bc%2FEM98 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/604.4.7 (KHTML, like Gecko) Version/11.0.2 Safari/604.4.7 Accept-Language: zh-cn Referer: http://localhost:8081/ Accept-Encoding: br, gzip, deflate

    返回报文:

    HTTP/1.1 200 OK Server: nginx/1.6.2 Date: Fri, 29 Dec 2017 03:26:31 GMT X-Powered-By: Express Transfer-Encoding: chunked Connection: Keep-alive jsonpiFuL4({"serverReceive":{"name":"��","site":"www.huangchengdu.com"},"serverSend":"hello,��.your site is https://www.huangchengdu.com"})

    从上面的报文我们可以返现。请求的callback参数的值和返回的响应体的名称是一样的。响应提就是一个普通的函数。服务器返回的数据作为函数的参数。

    XSS攻击


    XSS的全称是Cross-site scripting,翻译过来就是跨站脚本。script可以跨域加载脚本这个特性,合理利用比如JSONP。如果不合理利用,比如某个坏人通过某种方式,让你的浏览器去加载恶意的javascrpt脚本,必然就会导致敏感信息被盗或者财务损失。最常见的就是XSS攻击,其实就是注入恶意脚本。真是凡事都有利有弊,就看如何使用了。常用的XSS攻击手段和目的有如下几种:

    • 盗用cookie,获取敏感信息。

    • 利用植入Flash,通过crossdomain权限设置进一步获取更高权限;或者利用Java等得到类似的操作。

    • 利用iframe、frame、XMLHttpRequest或上述Flash等方式,以(被攻击)用户的身份执行一些管理动作,或执行一些一般的如发微博、加好友、- 发私信等操作。

    • 利用可被攻击的域受到其他域信任的特点,以受信任来源的身份请求一些平时不允许的操作,如进行不当的投票活动。

    • 在访问量极大的一些页面上的XSS可以攻击一些小型网站,实现DDoS攻击的效果。

    如果某一个字符串里面有var a = 1;;var b = 2;这种类型的字符串。而且我们刚好要通过script标签加载。那么他就会弹出一个我是你大爷。避免的方式就是把存在这种可能性的地方都处理过,如果包含类似

    mvc与mvvc


    MVC(Model-View-Controller)

    M-模型-数据处理-其实就是数据

    V-视图-其实就是用户界面

    C-控制器-其实就是用户逻辑

    MVVC(Model-View-ViewModel):实现的方式是DOM的事件监听

    模型M 指的是后端传递的数据

    视图V 指的是所有看到的页面

    视图模型 mvvc模式的核心,它是连接view和model的桥梁

    window.onload和$(document).ready()的区别,浏览器加载转圈结束时哪个时间点?


    1、执行时间上的区别:window.onload必须等到页面内(包括图片的)所有元素加载到浏览器中后才能执行。而$(document).ready(function(){})是DOM结构加载完毕后就会执行。

    2、编写个数不同:window.onload不能同时写多个,如果有多个window.onload,则只有最后一个会执行,它会把前面的都覆盖掉。$(document).ready(function(){})则不同,它可以编写多个,并且每一个都会执行。

    3、简写方法:window.onload没有简写的方法,$(document).ready(function(){})可以简写为$(function(){})。

    另外:由于在$(document).ready()方法内注册的事件,只要DOM就绪就会被执行,因此可能此时元素的关联文件未下载完,例如与图片有关的HTML下载完毕,并且已经解析为DOM树了,但很有可能图片还未加载完毕,所以例如图片的高度和宽度这样的属性此时不一定有效。

    要解决这个问题,可以使用JQuery中另一个关于页面加载的方法---load()方法。load()方法会在元素的onload事件中绑定一个处理函数。如果处理函数绑定在元素上,则会在元素的内容加载完毕后触发。如:$(window).load(function(){})=====window.onload = function(){}...

    setTimeout和setInterval区别,如何互相实现?


    setTimeout() 定义和用法:

    定义:

    setTimeout()方法用于在指定毫秒数后再调用函数或者计算表达式(以毫秒为单位)

    语法:

    setTimeout(code,millisec)

    code:必需,要调用的函数后要执行的 JavaScript 代码串;millisec:必需,在执行代码前需等待的毫秒数。

    setTimeout() 只执行函数一次,如果需要多次调用可以使用 setInterval(),或者在函数体内再次调用setTimeout()

    示例代码:延迟1秒弹出 Hello

    // 延迟1秒弹出 Hello setTimeout(function(){ alert("Hello"); }, 1000);

    setInterval() 定义和用法:

    定义:

    setInterval() 方法用于按照指定的周期(以毫秒计)来循环调用函数或计算表达式,直到 clearInterval() 被调用或窗口关闭,由 setInterval() 返回的 ID 值可用作 clearInterval() 方法的参数。

    语法:

    setInterval(code,millisec[,"lang"])

    code:必需,要调用的函数或要执行的JavaScript 代码串;millisec:必须,周期性执行或调用 code 之间的时间间隔,以毫秒计。

    setInterval() 会不停的调用函数,直到clearInterval() 被调用或者窗口被关闭,由 setInterval() 返回的ID值可用作 clearInterval() 方法的参数。

    示例代码:一直显示当前时间,点击停止不继续

    显示当前时间:

    setTimeout() 方法只运行一次,也就是说当达到设定的时间后就开始运行指定的代码,运行完后就结束了,次数是一次。

    setInterval() 是循环执行的,即每达到指定的时间间隔就执行相应的函数或者表达式,只要窗口不关闭或 clearInterval() 调用就会无限循环下去。

    伪类和伪元素区别


    前端高频面试题总结(看完这些面试轻轻松松)_第158张图片
    前端高频面试题总结(看完这些面试轻轻松松)_第159张图片

    伪元素其实相当于伪造了一个元素,例如before,first-letter达到的效果就是伪造了一个元素,然后添加了其相应的效果而已;而伪类没有伪造元素,例如first-child只是给子元素添加样式而已。

    伪元素和伪类之所以这么容易混淆,是因为他们的效果类似而且写法相仿,但实际上 css3 为了区分两者,已经明确规定了伪类用一个冒号来表示,而伪元素则用两个冒号来表示。

    数组去重


    1.第一种方式就是最简单的set去重(o(n))

    var arr = [1,2,2,4,3,4,1,3,2,7,5,6,1]

    var newArr = new Set(arr)

    2.第二种方式就是用indexOf来去重(o(n^3))

    判断新数组中某个数字是否存在

    function fn(arr){ let newArr = [] arr.forEach((val)=>{ if(newArr.indexOf(val) == -1){ newArr.push(val) } }) return newArr }

    function fn(arr) {

      return arr.filter((item, index, arr) => arr.indexOf(item) === index)

    }

    3.第三种方式普通去重(o(n^3))

    for(var i=0;i

    4.键值去重(o(n^3))

    根据键值是唯一的来去重

    function fn(arr){

    let arr1 = [],

    arr2 = []

    arr.forEach((val)=>{

    arr1[val]=val

    })

    //arr1数组会存在空的情况

    //所以返回arr2

    arr1.forEach((val)=>{

    if(!!val){

    arr2.push(val)

    }

    })

    return arr2

    }

    5.sort排序后去重(o(n^2))

    只比set复杂度低

    function fn(arr){ let newArr = [] arr.sort((a,b)=>{ return a-b }) arr.forEach((val,index)=>{ if(val != arr[index+1]){ newArr.push(val) } }) return newArr }

    vue2和vue3区别


    vue2 的双向数据绑定是利用ES5 的一个 API Object.definePropert()对数据进行劫持 结合 发布订阅模式的方式来实现的。

    vue3 中使用了 es6 的 ProxyAPI 对数据代理。

    相比于vue2.x,使用proxy的优势如下

    defineProperty只能监听某个属性,不能对全对象监听

    可以省去for in、闭包等内容来提升效率(直接绑定整个对象即可)

    可以监听数组,不用再去单独的对数组做特异性操作 vue3.x可以检测到数组内部数据的变化

    二. Vue3支持碎片(Fragments)

    就是说在组件可以拥有多个根节点。

    vue2

    vue3

    三. Composition API

    Vue2与Vue3 最大的区别 — Vue2使用选项类型API(Options API)对比Vue3合成型API(Composition API)

    旧的选项型API在代码里分割了不同的属性: data,computed属性,methods,等等。新的合成型API能让我们用方法(function)来分割,相比于旧的API使用属性来分组,这样代码会更加简便和整洁。

    vue2

    export default {

    props: {

    title: String

    },

    data () {

    return {

    username: '',

    password: ''

    }

    },

    methods: {

    login () {

    // 登陆方法

    }

    },

    components:{

    "buttonComponent":btnComponent

    },

    computed:{

    fullName(){

    return this.firstName+" "+this.lastName;

    }

    }

    }

    vue3

    export default {

    props: {

    title: String

    },

    setup () {

    const state = reactive({ //数据

    username: '',

    password: '',

    lowerCaseUsername: computed(() => state.username.toLowerCase()) //计算属性

    })

    //方法

    const login = () => {

    // 登陆方法

    }

    return {

    login,

    state

    }

    }

    }

    四. 建立数据 data

    Vue2 - 这里把数据放入data属性中

    export default {

    props: {

    title: String

    },

    data () {

    return {

    username: '',

    password: ''

    }

    }

    }

    在Vue3.0,我们就需要使用一个新的setup()方法,此方法在组件初始化构造的时候触发。

    使用以下三步来建立反应性数据:

    从vue引入reactive

    使用reactive()方法来声名我们的数据为响应性数据

    使用setup()方法来返回我们的响应性数据,从而我们的template可以获取这些响应性数据

    import { reactive } from 'vue'

    export default {

    props: {

    title: String

    },

    setup () {

    const state = reactive({

    username: '',

    password: ''

    })

    return { state }

    }

    }

    template使用,可以通过state.username和state.password获得数据的值。

    五. 生命周期钩子 — Lifecyle Hooks

    Vue2--------------vue3

    beforeCreate -> setup()

    created -> setup()

    beforeMount -> onBeforeMount

    mounted -> onMounted

    beforeUpdate -> onBeforeUpdate

    updated -> onUpdated

    beforeDestroy -> onBeforeUnmount

    destroyed -> onUnmounted

    activated -> onActivated

    deactivated -> onDeactivated

    setup() :开始创建组件之前,在beforeCreate和created之前执行。创建的是data和method

    onBeforeMount() : 组件挂载到节点上之前执行的函数。

    onMounted() : 组件挂载完成后执行的函数。

    onBeforeUpdate(): 组件更新之前执行的函数。

    onUpdated(): 组件更新完成之后执行的函数。

    onBeforeUnmount(): 组件卸载之前执行的函数。

    onUnmounted(): 组件卸载完成后执行的函数

    若组件被包含,则多出下面两个钩子函数。

    onActivated(): 被包含在中的组件,会多出两个生命周期钩子函数。被激活时执行 。

    onDeactivated(): 比如从 A组件,切换到 B 组件,A 组件消失时执行。

    六.父子传参不同,setup() 函数特性

    总结:

    1、setup 函数时,它将接受两个参数:(props、context(包含attrs、slots、emit))

    2、setup函数是处于 生命周期函数 beforeCreate 和 Created 两个钩子函数之前的函数

    3、执行 setup 时,组件实例尚未被创建(在 setup() 内部,this 不会是该活跃实例的引用,即不指向vue实例,Vue 为了避免我们错误的使用,直接将 setup函数中的this修改成了 undefined)

    4、与模板一起使用:需要返回一个对象 (在setup函数中定义的变量和方法最后都是需要 return 出去的 不然无法再模板中使用)

    5、使用渲染函数:可以返回一个渲染函数,该函数可以直接使用在同一作用域中声明的响应式状态

    注意事项:

    1、setup函数中不能使用this。Vue 为了避免我们错误的使用,直接将 setup函数中的this修改成了 undefined)

    2、setup 函数中的 props 是响应式的,当传入新的 prop 时,它将被更新。但是,因为 props 是响应式的,你不能使用 ES6 解构,因为它会消除 prop 的响应性。

    如果需要解构 prop,可以通过使用 setup 函数中的toRefs 来完成此操作:

    父传子,props

    import { toRefs } from 'vue'

    setup(props) {

    const { title } = toRefs(props)

    console.log(title.value)

    onMounted(() => {

    console.log('title: ' + props.title)

    })

    }

    子传父,事件 - Emitting Events

    举例,现在我们想在点击提交按钮时触发一个login的事件。

    在 Vue2 中我们会调用到this.$emit然后传入事件名和参数对象。

    login () {

    this.$emit('login', {

    username: this.username,

    password: this.password

    })

    }

    在setup()中的第二个参数content对象中就有emit,这个是和this.$emit是一样的。那么我们只要在setup()接收第二个参数中使用分解对象法取出emit就可以在setup方法中随意使用了。

    然后我们在login方法中编写登陆事件

    另外:context 是一个普通的 JavaScript 对象,也就是说,它不是响应式的,这意味着你可以安全地对 context 使用 ES6 解构

    setup (props, { attrs, slots, emit }) {

    // ...

    const login = () => {

    emit('login', {

    username: state.username,

    password: state.password

    })

    }

    // ...

    }

    3、 setup()内使用响应式数据时,需要通过.value获取

    import { ref } from 'vue'

    const count = ref(0)

    console.log(count.value) // 0

    4、从 setup() 中返回的对象上的 property 返回并可以在模板中被访问时,它将自动展开为内部值。不需要在模板中追加 .value

    5、setup函数只能是同步的不能是异步的

    七. vue3 Teleport瞬移组件

    Teleport一般被翻译成瞬间移动组件,实际上是不好理解的.我把他理解成"独立组件",

    他可以那你写的组件挂载到任何你想挂载的DOM上,所以是很自由很独立的

    以一个例子来看:编写一个弹窗组件

    在app.vue中使用的时候跟普通组件调用是一样的

    要是在app.vue文件中使用的时候,modal是在app的 DOM节点之下的,父节点的dom结构和css都会给modal产生影响

    于是产生的问题

    modal被包裹在其它组件之中,容易被干扰

    样式也在其它组件中,容易变得非常混乱

    Teleport 可以把modal组件渲染到任意你想渲染的外部Dom上,不必嵌套在#app中,这样就可以互不干扰了,可以把Teleport看成一个传送门,把你的组件传送到任何地方

    使用的时候 to属性可以确定想要挂载的DOM节点下面

    在public文件夹下的index.html中增加一个节点

    <%= htmlWebpackPlugin.options.title %>

    We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.

    mvvm和mvp和mvc


    mvc:经典模式

    MVC全名为Model View Controller ,是模型(Model)- 视图(View)- 控制器(Controller)的缩写。他是1970年代被引入到软件设计大众的。MVC模式致力于关注点的切分,这意味着model和controller的逻辑是不与用户界面(View)挂钩的。因此,维护和测试程序变得更加简单容易。

    [图片上传失败...(image-98e8bd-1630660921001)]

    • Model层:模型(用于封装业务逻辑相关的数据以及对数据的操纵)

    • View层:视图(渲染图形化界面,也就是所谓的UI界面)

    • Controller层:控制器(M和V之间的连接器,主要处理业务逻辑,包括显示数据,界面跳转,管理页面生命周期等)

    **标准MVC工作模式: **当有用户的行为触发操作时,控制器(Controller)更新模型,并通知视图(V)和模型(M)更新,这时视图(V)就会向模型(M)请求新的数据,这就是标准MVC模式下Model,View 和 Controller 之间的协作方式。

    MVC优点:

    1. 耦合性低,视图层和业务层分离,这样就允许更改视图层代码而不用重新编译模型和控制器代码;

    1. 重用性高;

    1. 生命周期成本低;

    1. MVC使开发和维护用户接口的技术含量降低;

    1. 可维护性高,分离视图层和业务逻辑层也使得WEB应用更易于维护和修改;

    1. 部署快。

    MVC缺点:

    1. 不适合小型,中等规模的应用程序,花费大量时间将MVC应用到规模并不是很大的应用程序通常会得不偿失。

    1. 视图与控制器间过于紧密连接,视图与控制器是相互分离,但却是联系紧密的部件,视图没有控制器的存在,其应用是很有限的,反之亦然,这样就妨碍了他们的独立重用。

    1. 视图对模型数据的低效率访问,依据模型操作接口的不同,视图可能需要多次调用才能获得足够的显示数据。对未变化数据的不必要的频繁访问,也将损害操作性能。

    MVP:MVP 模式将 Controller 改名为 Presenter,同时改变了通信方向。

    MVP全名为Model View Presenter ,是由MVC演变而来,它和MVC的相同之处在于:Controller / Presente都是负责业务逻辑,Model管理数据,View负责显示。不过在MVP中View并不直接与Model交互,它们之间的通信是通过Presenter (MVC中的Controller)来进行的,即使用 Presenter 对视图和模型进行了解耦,让它们彼此都对对方一无所知,沟通都通过 Presenter 进行。

    [图片上传失败...(image-ef95e0-1630660921001)]

    • Model层:模型(用于封装业务逻辑相关的数据以及对数据的操纵)

    • View层:视图(渲染图形化界面,也就是所谓的UI界面)

    • Presenter层:控制器(M和V之间的连接器,主要处理业务逻辑,包括显示数据,界面跳转,管理页面生命周期等)

    **标准MVP工作模式: **在 MVP 中,Presenter 可以理解为松散的控制器,其中包含了视图的 UI 业务逻辑,所有从视图发出的事件,都会通过代理给 Presenter 进行处理;同时,Presenter 也通过视图暴露的接口与其进行通信。

    MVP特点:

    1. M、V、P之间双向通信。

    1. View 与 Model 不通信,都通过 Presenter 传递。Presenter完全把Model和View进行了分离,主要的程序逻辑在Presenter里实现。

    1. View 非常薄,不部署任何业务逻辑,称为”被动视图”(Passive View),即没有任何主动性,而 Presenter非常厚,所有逻辑都部署在那里。

    1. Presenter与具体的View是没有直接关联的,而是通过定义好的接口进行交互,从而使得在变更View时候可以保持Presenter的不变,这样就可以重用。不仅如此,还可以编写测试用的View,模拟用户的各种操作,从而实现对Presenter的测试–从而不需要使用自动化的测试工具。

    MVP优点:

    1. 模型与视图完全分离,我们可以修改视图而不影响模型;

    1. 可以更高效地使用模型,因为所有的交互都发生在一个地方——Presenter内部;

    1. 我们可以将一个Presenter用于多个视图,而不需要改变Presenter的逻辑。这个特性非常的有用,因为视图的变化总是比模型的变化频繁;

    1. 如果我们把逻辑放在Presenter中,那么我们就可以脱离用户接口来测试这些逻辑(单元测试)。

    MVP缺点:视图和Presenter的交互会过于频繁,使得他们的联系过于紧密。也就是说,一旦视图变更了,presenter也要变更。

    MVVM

    MVVM全名为Model View ViewModel。这个模式提供对View和View Model的双向数据绑定。这使得View Model的状态改变可以自动传递给View。典型的情况是,View Model通过使用obsever模式(观察者模式)来将View Model的变化通知给model。

    [图片上传失败...(image-dc3ca7-1630660921001)]

    • Model层:Model层代表了描述业务逻辑和数据的一系列类的集合。它也定义了数据修改和操作的业务规则。

    • View层:View代表了UI组件,像CSS,JQuery,html等。他只负责展示从Presenter接收到的数据。也就是把模型转化成UI。

    • View Model层:View Model负责暴漏方法,命令,其他属性来操作VIew的状态,组装model作为View动作的结果,并且触发view自己的事件。

    MVVM模式关键点:

    1. 用户和View交互。

    1. View和ViewModel是多对一关系。意味着一个ViewModel只映射多个View。

    1. View持有ViewModel的引用,但是ViewModel没有任何View的信息。

    1. View 和ViewModel之间有双向数据绑定关系。

    MVVM优点:

    1. 低耦合,视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的”View”上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。

    1. 可重用性,可以把一些视图逻辑放在一个ViewModel里面,让很多view重用这段视图逻辑。

    1. 独立开发,开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计,使用Expression Blend可以很容易设计界面并生成xml代码。

    1. 可测试,界面向来是比较难于测试的,而现在测试可以针对ViewModel来写。

    三种模式的区别

    MVC 是世界上最低级、最原始的 UI 模式;MVC 就是在 V 上绑定 M,然后 C 负责处理界面整个提交请求,并且一遍遍地刷新整个 V。这种机制。所以 MVC 的标志是“初级、单向绑定、一遍遍刷新UI”。

    MVP 则是深入到程序的“骨髓”,UI设计模板与 MVP 事件定义绑定,让程序员可以捕获这么一个组件的丰富的事件,然后在事件处理过程中又去从控件树上去直接访问其它所有控件,直接修改其属性。开发的精力很大程度上用在学习各种控件的内部机制上,学习曲线陡峭。所以MVP的标志是“复杂、事件驱动、精细到每一个控件层次”。

    MVVM 则是在 MVP 上的改进,它隔离了控件操作层,UI 模板上各种控件直接跟 VM 层的属性绑定,使得 VM 属性改变时自动更新 UI 控件,反之 UI 控件的值改变时又自动更新 VM 属性。这样编程的方式就不是去一大堆控件事件处理,而是写少量的 VM 属性更改行为代码。开发精力绝大部分都放在业务与UI的绑定上,而并不需要研究控件内部机制。

    三种设计模式的应用

    MVC模式。

    React使用的是MVC模式。所有MVC框架都是单向数据流的。

    特色:

    • 使用Virtual DOM

    • 提供了响应式(Reactive) 和组件化 (Composable) 的视图组件。

    • 将注意力集中保持在核心库,而将其他功能如路由和全局状态管理交给相关的库。

    注:react 实际上是一个“伪MVC”,它其实是 MVP 的,但是它深知 MVP 模式的弊病,它明明是基于组件并且绑定了组件的 change 事件的,但是它有使用虚拟DOM的方式来一遍遍刷新UI控件(并且为了解决性能问题,有各种负责和诡异的避免全局刷新UI树的反模式操作)。所以虽然 React 自称为 MVC模式,但是实际上它是 MVP 的变种。

    MVP模式。

    JQuery 是非常经典的 MVP 编程模式

    MVVM模式。

    Knockout、AngularJS、Vue 等可以看作是 MVVM 模式

    Angular使用的MVVM模式。当触发UI事件,ajax请求或者 timeout 延迟,会触发脏检查。这时会调用

    watch函数,最后把所有的变化全部更新,调用apply()方法把新的数据渲染到页面上。

    优点:一次检测会收集所有的数据变化,然后统一更新UI,大大减少了操作 DOM 的次数。

    缺点:只要有ui或ajax或settimeout操作时就会进行检查,且当watcher之间相互影响的时候,更会触发多次$digest循环,这样watcher一多,就会很影响性能。

    注:AngularJS 其实在 MVVM 上做的不是很好,倾向于 MVP。只有 Knockout 是实现了经典的 MVVM 设计模式,而且有几个性能相关的特性(例如自动延迟 UI 刷新、自动抽稀无用的 UI 刷新操作)可以将性能提高(相对于其它许多 web 前端框架)至少几十倍。

    Vue一定意义上算是React和Angular的集大成者。它吸取了MVVM的数据管理思想,同时应用了React的virtual Dom算法。它使用了双向数据绑定来满足开发的便捷,但是它不同组件之间又使用单向数据流,来保证数据的可控性。它使用了很多Angular的指令语法,但是它革新了Angular的脏数据检查机制,使用数据劫持的方法来触法数据检查机制。它借鉴了React的组件化思想,大大增加了前端工程的结构规范化。

    注:Vue 内部使用了 Object.defineProperty() 来实现双向绑定,通过这个函数可以监听到 set 和 get 的事件。

    总结

    MVC 只是把控件跟 M 绑定,一遍遍刷新 UI。而 MVP 则是把控件跟事件单向绑定,它的假设是程序员最爱写低级的代码来操作控件。而 MVVM 则是把控件跟 VM 双向绑定,它的假设是交互界面设计时最爱写高层次一些的声明来操作用户业务行为上的变化。

    es6和html5和css3


    1、更加语义化的元素。 article、footer、header、nav、section

    2、本地化储存。 localStorage 和 sessionStorage (强缓存与协商缓存)

    3、离线应用,离线缓存。 manifest

    4、拖曳以及释放的api。 Drag and drop

    5、媒体播放。 video 和 audio

    6、增强表单控件。 calendar、date、time、email、url、search

    7、地理位置。 Geolocation

    8、多任务。 webworker

    普通的 Worker 可以在需要大量计算的时候使用,创建新的线程可以降低主线程的计算压力,不会导致 UI 卡顿。SharedWorker 主要是为不同的 window、iframes 之间共享数据提供了另外一个解决方案。ServiceWorker 可以缓存资源,提供离线服务或者是网络优化,加快 Web 应用的开启速度,更多是优化体验方面的。

    9、全双工通信协议。 websocket

    在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

    10、历史管理 history

    11、跨域资源共享(CORS) Access-Control-Allow-Origin

    12/页面可见性改变事件 visibilitychange

    13、跨窗口通信 PostMessage

    14、Form Data 对象

    15、绘画:canvas

    2.css3

    1、盒子模型

    在标准的盒模型中一个盒子的宽度是:margin(左右外边距)+padding(左右内边距)+border(左右边框)+内容的(width).

    IE盒子:内容的(width)+margin(左右)(这里的内容width包含了padding(左右内边距)+border(左右边框))

    两种盒子模型转换通过box-sizing

    2、选择器

    属性选择器

    input[type=“password”] {

    border: 1px solid red;

    }

    结构伪类选择器

    input:first-child {

    border: 1px solid green;

    }

    伪类选择器

    ::before ::after

    3、其他属性

    阴影:text-shadow box-shadow

    图片模糊:filter:blur(0px)括号的值越大越模糊

    背景图属性background-size

    透明:opacity transparent

    渐变:background: linear-gradient(to top right,red 0%, yellow 30px, green 100%);

    4、变形transform(2D,3D)

    transform-origin:x% y%;

    transform:translateX,translateY,translateZ,rotateX,rotateY,scaleX,scaleY,scaleZ,skewX,skewY

    5、动画

    过渡动画:transition: all 1s ease 10ms;

    帧动画:animation: move 2s linear infinite normal forwards 1s;

    6、媒体查询

    @media (min-width: 721px) and (max-width: 1440px) {

    / min-width相当于>=,max-width相当于<= /

    .mediaBox {

    background: green;

    }

    }

    3、ES6

    1、var let const

    var let const声明方式 区别块级作用域和变量提升

    2、扩展运算符…

    3、super关键字

    4、set map

    1.Map是键值对,Set是值得集合,当然键和值可以是任何的值;

    2.Map可以通过get方法获取值,而set不能因为它只有值;

    3.都能通过迭代器进行for…of遍历;

    4.Set的值是唯一的可以做数组去重,Map由于没有格式限制,可以做数据存储;

    5、模板字符串

    6、promise

    let、const、var


    1.var是ES5提出的,let和const是ES6提出的。

    2.const声明的是常量,必须赋值

    1)一旦声明必须赋值,不能使用null占位。

    2)声明后不能再修改

    3)如果声明的是复合类型数据,可以修改其属性

    3.let和var声明的是变量,声明之后可以更改,声明时可以不赋值

    4.var允许重复声明变量,后一个变量会覆盖前一个变量。let和const在同一作用域不允许重复声明变量,会报错。

    5.var声明的变量存在变量提升(将变量提升到当前作用域的顶部)。即变量可以在声明之前调用,值为undefined。

    let和const不存在变量提升。即它们所声明的变量一定要在声明后使用,否则报ReferenceError错。

    6.var不存在块级作用域。let和const存在块级作用域。

    ES5中作用域有:全局作用域、函数作用域。没有块作用域的概念。

    ES6(简称ES6)中新增了块级作用域。块作用域由 { } 包括,if语句和for语句里面的{ }也属于块作用域。

你可能感兴趣的:(前端,vue.js,javascript)