前端面试题整理 Vue(会持续更新的~)

导读:本篇文章讲解 前端面试题整理 Vue(会持续更新的~),希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

1.Vue 不同环境配置不同的接口地址;

在项目中,前端请求访问的地址如果有跨域,我们会在config–>index.js中配置代理。
在这里插入图片描述

这样前端请求就可以使用'/api/接口名称',但是在生产环境下,我们不需要接口请求前面加'/api',所以就需要判断开发环境和生产环境。
1)
    config -> dev.env.js  添加开发接口地址
    config -> prod.env.js  添加生产环境的地址
2)
    在封装axios时,添加判断:
    if (location.hostname == '正式的域名') { 
        baseUrl = '正式地址'
    } else { //测试环境
        baseUrl = '测试地址'
    }

    axios.defaults.baseURL = baseUrl

2.用户未登录进入该url的登录拦截逻辑:

1.首先在定义路由的时候需要添加自定义字段(requireAuth)字段可以自己设置名称,判断该路由的访问是否需要登录,如果用户已经登录,顺利进入该路由,否则就进入登录页。在路由管理页面添加meta,在meta字段里设置。
    meta:{requireAuth:true}// 添加该字段,true表示进入这个路由是需要登录的
2.定义完路由后,利用vue-router的钩子函数beforeEach对路由进行判断;
router.beforeEach((to, from, next) => { 
    if (to.meta.requireAuth) { // 判断该路由是否需要登录权限 
        if (store.state.token) { // 通过vuex state获取当前的token是否存在 
            next();
        } else { 
            next({ 
                path: '/login', 
                query: {
                    redirect: to.fullPath
                } // 将跳转的路由path作为参数,登录成功后跳转到该路由 
            }) 
        } 
        } else { 
            next(); 
        }
   })

3.axios是什么?怎么使用?

axios是一个基于promise的HTTP请求库,简单地说就是可以发送get、post请求,可以用在浏览器和node.js中。
axios的特性:
    1)可以在浏览器中发送XMLHttpRequests
    2)可以在node.js中发送http请求
    3)支持Promise API
    4)拦截请求和响应
    5)转换请求数据和响应数据
    6)能够取消请求
    7)自动转换json数据
    8)客户端支持保护安全免受 XSRF 攻击

4.VueX是什么?哪种场景能使用它?

1)VueX是一个专门为vue构建的状态集管理。主要为了解决组件之间状态共享的问题。强调的是集中式管理。主要是便于维护、便于解耦,不是所有项目都适合vuex,如果不是构建大型项目,会使代码变得繁琐多余。
2)VueX的核心
    state:存放数据
    mutations:变更状态(同步的)
    getters:
    actions:调用mutations,更改状态的。(可以异步)
    modules
    

5.路由的钩子函数

路由的钩子函数主要是用来拦截导航,让它完成跳转和取消
主要分为全局和局部
全局的:
    1)beferEach
    2)afetrEach

6.vue的生命周期详解(必看)

vue生命周期分为四个阶段
creating
mounting
updating
destroying

beforeCreated:el和data都未初始化(可以加loading)
Created:data数据初始化,el未初始化(结束loading)
beforeMount:完成el和data初始化(虚拟DOM)
mounted:挂载完成,真实DOM渲染完成(发起请求,拿数据,渲染DOM)
beforeUpdate:组件更新前的函数,数据更新了,但是,vue(组件)对象对应的dom中的内部(innerHTML)没有变,所以叫作组件更新前
update:组件更新之后执行的函数,vue(组件)对象对应的dom中的内部(innerHTML)改变了,所以,叫作组件更新之后
beforeDestroy:组件销毁之前调用,在这一步,实例仍然可以完全可用(可在此处清除定时器,清除事件绑定)
destroyed:Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁

其中 created 和 mounted 比较重要,一个是data数据和事件的初始化,一个是html 模板 挂载渲染到页面完毕

附加: keep-alive 方法

actived() 组件加上keep-alive,进入组件触发的方法
deactived() 离开组件的时候触发的方法

7.路由懒加载

1)vue异步组件技术,vue-router配置路由,使用路由的异步组件技术,可以实现按需加载。但是这种情况下,一个组件生成一个js文件。
{
    path:'/home',
    name:'home'.
    component:resolve => require(['@/components/home'],resolve)
}
2)路由懒加载(使用import)
const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
{
    path:'/home',
    name:'home'.
    component:Foo
}

在build目录下找到webpack.prod.conf.js文件,将output修改为
output: {
    path: config.build.assetsRoot,
    filename: utils.assetsPath('js/[name].[chunkhash].js'),//文件格式,文件名.文件哈希
    chunkFilename: utils.assetsPath('js/[name].[chunkhash].js')//文件切割后的文件名称。
    这里的name对应的就是路由中引入文件时候的webpackChunkName
}
3)webpack提供的require.ensure技术,也可以按需加载,多个路由指定相同的chunkName,会合并打包成一个js文件。
{
    path:'/home',
    name:'home'.
    component:resolve=>require.ensure([],() => resolve(require('../components/PromiseDemo')),home)
}

8.封装组件过程

1)新建组件,组件包含template、script、style
2)父组件中,使用import引入组件 import 组建名称 form 组件路径
3)父组件中,components注册组件 components:{ 组件名称 }

9.vue路由传参方式

<div v-for="article in articles" @click="getDescribe(article.id)"></div>
1)getDescribe(id){
    this.$router.push({
        path:'/describe/${id}'
    })
}
对应的路由配置:
{
 path: '/describe/:id',
 name: 'Describe',
 component: Describe
}
获取参数:this.$route.params.id;

2)getDescribe(id){
    this.$router.push({
        name:'/describe',
        params:{
            id:id
        }
    })
}
获取参数:this.$route.params.id

3)getDescribe(id){
    this.$router.push({
        path:'/describe',
        query:{
            id:id
        }
    })
}
获取参数:this.$route.query.id;    //query方式参数会显示在url的后面

10.插槽的作用?

**匿名插槽:**
    子组件:
    <template>
        <h3>test-slot</h3>
        //父组件里的span会替换掉slot所以这里的123是看不见的
        //如果父组件在使用子组件testSlot的时候不在里面加内容则这里的slot会显示出来          
        <slot>123</slot> 
    </template>
    父组件:
    <template>
      <div id="app">
        <test-slot>
          <span>我是父组件里的文字,但是我要被放到子组件里</span>
        </test-slot>
     </div> 
   </template> 
**渲染结果:**
    test-slot
    我是父组件里的文字,但是我要被放到子组件里

**多个插槽也叫具名插槽:**
子组件:
    <template>
        <h3>test-slot</h3>
        //父组件里的span会替换掉slot所以这里的123是看不见的
        //如果父组件在使用子组件testSlot的时候不在里面加内容则这里的slot会显示出来          
        <slot name='header'>123</slot> 
        <slot>123</slot> 
        <slot name='footer'>123</slot> 
    </template>
父组件:
    <template>
        <h3>多个具名插槽</h3>
        <div slot='header'>头部内容</div>
        <div>内容部分</div>
        <div slot='footer'>底部内容</div>
    </template>
**渲染结果:**
    多个具名插槽
    头部内容
    内容部分
    底部内容

**作用域插槽:** 
作用域插槽是一种特殊类型的插槽,子组件的值传到父组件使用
子组件:
    子组件props里接收一个父组件传递的数组,在作用域插槽slot里边,绑定数组的属性。
    <template>
      <div class="hello">
        <slot :cname="items[2].cname"></slot> 
        <slot :addr="items[2].addr"></slot> 
        <slot age="18"></slot> 
      </div>
    </template>

    <script>
        export default {
        
          data () {
            return {
              num:100
            }  
          },
          props:['items'],
          methods:{
            
          },
          created(){
            console.log('items',this.$props.items);
          }
        }
    </script>

父组件:
    在test-slot子组件标签上通过:item='items'给子组件传递数组,通过slot-scope='props'获取子组件作用域插槽所有的属性值
    <template>
      <div id="app">
        <h2>app</h2>
         <test-slot :items="items">
           <template slot-scope="props">
             <span>{{ props.addr }}</span>
             <span>{{ props.cname }}</span>
             <span>{{ props.age }}</span>
           </template>
         </test-slot>
      </div>
    </template>
    
    <script>
    import testSlot from './components/testSlot.vue'
    export default {
      data (){
        return {
          items:[
            { text:'文字1' , cname:'tom' , addr:'usa' },
            { text:'文字2' , cname:'wangwu' , addr:'uk' },
            { text:'文字3' , cname:'zhangsan' , addr:'un' }
          ]
        }
      },
      methods:{
        
      },
      components:{
        testSlot
      }
    }
    </script>
**渲染结果:**
zhangsan un 18  

11 了解过MVC吗,说下对MVC的理解

  MVC:Model View Controller。Model 指 模型,用于存储数据;
  View  指 视图,用于展示数据;Controller 指 控制器,用于调用其他子服务,使Model 和 View 解耦合。
  Model 和 view 不直接通信,而是通过controller 联系起来,Controller 相当于 外观模式的应用。

*12 为什么在项目中data需要使用return返回数据呢?

不使用return包裹的数据会在项目的全局可见,会造成变量污染
  使用return包裹后数据中变量只在当前组件中生效,不会影响其他组件

13 说下vue里面的 computed 和 watch 的区别

computed 计算属性,watch 监听变化
           区别是
           computed 是计算值
               应用:简化 template 里面 {{}} 的计算和处理 props 或 $emit 的传值
               具有缓存性,页面重新渲染值不计算,只有当被计算的值发生变化才计算

           watch 是观察值是否发生变化
               应用:监听 props,$emit 或本组件的值执行异步操作
               无缓存性,页面重新渲染就算值不变化也会执行
               watch 里面还要注意下 immediate 和 deep 属性

           watch与computed的区别是:
watch更加适用于监听某一个值的变化并做对应的操作,比如请求后台接口等; 

而computed适用于计算已有的值并返回结果

参考文章:https://segmentfault.com/a/1190000012948175?utm_source=tag-newest#articleHeader10https://blog.csdn.net/lhban108/article/details/82465547

14 说一下你知道的http的状态码

200 请求资源成功

400 客户端请求格式错误

403 需要客户端身份验证

404 请求资源不存在

413 请求资源过大

500 服务器端错误

3xx 一般为重定向

详细链接:https://tool.oschina.net/commons?type=5
注意: 301和302得区别

301:被请求的资源已永久移动到新位置,并且将来任何对此资源的引用都应该使用本响应返回的若干个 URI 之一。

302:请求的资源现在临时从不同的 URI 响应请求。由于这样的重定向是临时的,客户端应当继续向原有地址发送以后的请求。

15 get和post的区别


**get** 参数直接放在url里面,并且传输的参数大小受不同浏览器限制,也不安全,毕竟直接暴露在url中,其值只能为字符串。

**post** 参数在报文体中,传输得容量比get大,参数不暴露出来相对安全。

**get** 发送一个数据包 ,**post** 发送两个
等等等等。。。。还有很多

详细链接:https://www.cnblogs.com/logsharing/p/8448446.html

16 对 ES6 新特性的了解
解构赋值、 let const 、块级作用域 、箭头函数 、promise。

letconst var 区别

**const** 声明的是**常量**,必须赋值
1)一旦声明必须赋值,不能使用null占位。
2)声明后不能再修改
3)如果声明的是复合类型数据,可以修改其属性

4> **let**和 **var** 声明的是变量,声明之后可以更改,声明时可以不赋值
5> var允许重复声明变量,后一个变量会覆盖前一个变量。let和const在同一作用域不允许重复声明变量,会报错
6> var声明的变量存在变量提升(将变量提升到当前作用域的顶部)。即变量可以在声明之前调用,值为undefined。
7> let和const不存在变量提升。即它们所声明的变量一定要在声明后使用,否则报ReferenceError错`在这里插入代码片`

var不存在块级作用域。let和const存在块级作用域。
ES5中作用域有:全局作用域、函数作用域。没有块作用域的概念。
ES6(简称ES6)中新增了块级作用域。块作用域由 { } 包括,if语句和for语句里面的{ }也属于块级作用域。

模板字符串

  1. 将表达式嵌入字符串中进行拼接。用**${}**来界定。
//ES5
var way = 'String'
console.log('ES5:' + way)

//ES6
let way = 'String Template'
console.log(`ES6: ${way}`)

2.多行字符串拼接

在ES5时我们通过反斜杠()来做多行字符串或者字符串一行行拼接。ES6反引号(“)直接搞定。

在这里插入图片描述

17 箭头函数和普通函数的区别

箭头函数 和 普通函数 的 this 指向不同

(1)箭头函数是匿名函数,不能作为构造函数,不能使用new

(2)箭头函数不绑定arguments,取而代之用rest参数…解决

(3)箭头函数不绑定this,会捕获其所在的上下文的this值,作为自己的this值

(4)箭头函数通过 call() 或 apply() 方法调用一个函数时,只传入了一个参数,对 this 并没有影响。

(5)箭头函数没有原型属性

(6)箭头函数不能当做Generator函数,不能使用yield关键字

参考文章https://www.cnblogs.com/biubiuxixiya/p/8610594.html

18.new 一个 箭头函数可以吗,为什么

箭头函数是匿名函数,不能作为构造函数,不能使用new

19 new 一个对象的过程

加粗样式当于运行构造函数:

this 指向这个对象,

对 this 进行属性赋值,

将 this 的 隐式原型 指向 构造函数的 显式原型,

返回这个对象

20 了解过 setTimeout 的原理
event loop机制
详细链接:https://www.cnblogs.com/xgqfrms/p/11399442.html

21.promise 和 setTimeout 的区别(微队列和宏队列)
扫到了目前的知识盲区:微任务队列 和 宏任务队列

promise.then 和 process.nextTick 都是 微任务

setTimout 和 setInterval 是 宏任务

微任务 比 宏任务 优先级高

setTimeout promise 遇到一起 promise先执行

详细链接:https://blog.csdn.net/qq_30376375/article/details/82990588

22.写一段 promise 和 setTimeout 的代码,问你输出结果

在这里插入图片描述
23.js 的基本数据类型
number string boolean undefined null

24 v-if与v-show的区别
相同点:都可以动态控制 DOM 元素的显示隐藏

区别:
v-if : 是将 DOM 元素整个添加或删除
v-show: 是为 DOM 元素添加css的样式display,设置 none 或者 是 block,DOM 元素 还是存在的

性能对比
v-if 有更高的切换消耗;
v-show 有更高的初始渲染消耗

应用场景

v-if 适合用于条件不大可能改变的情境下;
v-show 适合用于 频繁切换;

25 vue 中双向数据绑定是如何实现的
在这里插入图片描述
26 Vue组件通信(父传子、子传父、兄弟通信)

父传子、子传父、兄弟通信(bus)、本地存储、vuex

27 Vue-router共有几种模式?默认是哪种?
history模式 hash模式 默认 hash模式

28 NextTick是什么
在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM

29 Vue-cli打包命令是什么?打包后会导致路径问题,应该在哪里修改

npm run build-环境-域名-打包文件夹 -平台
打包后会项目中生成一个dist文件夹
在打包之前,需要将文件中config文件夹下的index.js中的 assetsPublicPath:”” 中的 / 改为 ./

30 assets和static的区别
assets目录中文件在打包的时候会进行打包压缩然后上传到打包好的目录,如果接口中的文件,不能放到assets中去。

static目录中的文件直接拷贝到打包好的目录中 不会进行压缩, 放第三方的json文件或者图片

31 null 和undefined 区别

null :null 表示一个值被定义了,定义为“空值”;
undefined 表示根本不存在定义。

  1. 变量被声明了,但没有赋值时,就等于 undefined
  2. 调用函数时,应该提供的参数没有提供,该参数等于 undefined
  3. 对象没有赋值的属性,该属性的值为 undefined
  4. 函数没有返回值时,默认返回 undefined
    在这里插入图片描述

null表示“没有对象”,即该处不应该有值。典型用法是:

  1. 作为函数的参数,表示该函数的参数不是对象
  2. 作为对象原型链的终点

32 隐藏一个元素有哪几种方法
opacity:0 z-index v-if v-show display:none visibility:hidden

display:none、visibility:hidden 和 opacity:0 的区别

display:none 隐藏后不占据额外空间,它会产生回流和重绘
visibility:hidden 和 opacity:0 元素虽然隐藏了,但它们仍然占据着空间,它们只会引起页面重绘
display:none 不会被子元素继承,但是父元素都不在了,子元素自然也就不会显示了
visibility:hidden 会被子元素继承,可以通过设置子元素visibility:visible 使子元素显示出来
opacity: 0 会被子元素继承,但是不能通过设置子元素opacity: 0使其重新显示

33 数组去重复的方法

方法1:简单粗暴的ES6方法Set,Set数据结构,它类似于数组,其成员的值都是唯一的。

var arr = [1, 2, 3, 2, 1, 3];
console.log(new Set(arr))//打印结果:Set(3) {1, 2, 3}

方法2:使用filter过滤函数去重。

var arr = [1, 2, 3, 1, 2, 3];
console.log(arr.filter((v, i, arr) => arr.indexOf(v) === i))//打印结果:(3) [1, 2, 3]

方法3:遍历数组法。

实现的思路:新建一个数组,遍历传入的数组,值不在新数组中就加入到该新数组;

注意:判断值是否在数组中可以用indexOf是ES5 方法,IE9以下不支持,需兼容低版本浏览器。

function unique(array) {
       var n = []; //一个新的临时数组 
        //遍历当前数组 
        for (var i = 0; i < array.length; i++) {
            if (n.indexOf(array[i]) == -1) n.push(array[i]);
            //如果当前数组的第i已经保存进了临时数组,那么跳过, 
            //否则把当前项push到临时数组里面 
        }
        return n;
    }
 console.log(unique([1, 2, 3, 1, 2, 3])) //打印结果:(3) [1, 2, 3]

方法4:利用splice()方法直接在原数组进行操作。

双层循环,外层循环元素,内层循环时比较值。

值相同时,则删去这个值。

注意:删除元素之后,需要将数组的长度也减1。

优点:简单易懂。

缺点:占用内存高,速度慢。

Array.prototype.unique = function () {
    var arr = this,
        i,
        j,
        len = arr.length;
    for (i = 0; i < len; i++) {
        for (j = i + 1; j < len; j++) {
            if (arr[i] == arr[j]) {
                arr.splice(j, 1);
                len--;
                j--;
            }
        }
    }
    return arr;
};
var a = [1, 2, 3, 1, 2, 3];
var b = a.unique();
console.log(b); //打印结果:(3) [1, 2, 3]

方法5:利用对象的属性不能相同的特点进行去重

Array.prototype.unique = function () {
    var arr = this,
        i,
        obj = {},
        result = [],
        len = arr.length;
    for (i = 0; i < arr.length; i++) {
        if (!obj[arr[i]]) { //如果能查找到,证明数组元素重复了
            obj[arr[i]] = 1;
            result.push(arr[i]);
        }
    }
    return result;
};
var a = [1, 2, 3, 1, 2, 3];
var b = a.unique();
console.log(b); //打印结果:(3) [1, 2, 3]

方法6:数组递归去重

Array.prototype.unique = function () {
    var arr = this,
        len = arr.length;
    arr.sort(function (a, b) { //对数组进行排序才能方便比较
        return a - b;
    })

    function loop(index) {
        if (index >= 1) {
            if (arr[index] === arr[index - 1]) {
                arr.splice(index, 1);
            }
            loop(index - 1); //递归loop函数进行去重
        }
    }
    loop(len - 1);
    return arr;
};
var a = [1, 2, 3, 1, 2, 3];
var b = a.unique();
console.log(b); //打印结果:(3) [1, 2, 3]

34 v-model是什么?怎么使用?
v-model用于表单数据的双向绑定,其实它就是一个语法糖,这个背后就做了两个操作:

v-bind绑定一个value属性
v-on指令给当前元素绑定input事件

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/79254.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!