尚品汇VUE项目实战相关面试题总结

文章目录

        • 1.v-show与v-if区别?
        • 2.开发项目的时候,优化手段有哪些?
        • 3.路由传递参数先关面试题
        • 4.axios二次封装
        • 5.函数防抖与节流面试题
        • 6.路由的跳转与传参
        • 7.搜索模块中的三级联动与过渡动画
        • 8.为什么会频繁的向服务器发请求获取三级联动的数据那?
        • 9.合并参数
        • 9.mock数据
        • 10.组件间通信
        • 11.用户在搜索模块要进行多次请求去渲染相应的数据

1.v-show与v-if区别?

v-show:通过样式display控制
v-if:通过操作DOM元素进行操作

2.开发项目的时候,优化手段有哪些?

1:v-show|v-if(首页|搜索底部是有Footer组件,而登录注册是没有Footer组件
Footer组件显示|隐藏,选择v-show|v-if)
2:按需加载(对于loadsh插件,element,它里面封装的函数功能很多)
3.函数防抖与节流
4.请求性能优化:

  • 请求数据优化
    发一个请求,需要向服务器携带参数:带100个参数 带1参数 【消耗宽带】
    对于给服务器携带的参数:如果数值为undefind,向服务器发请求的时候,参数步携带给服务器的
  • 请求的次数优化:
    1.TypeNav三级联动性能优化?
    - 项目:home切换到search或者search切换到home,你会发现一件事情,组件在频繁的向服务器发请求获取三级联动的数据进行展示。
    - 项目中如果频繁的向服务器发请求,很好性能的,因此咱们需要进行优化。
    2.为什么会频繁的向服务器发请求获取三级联动的数据那?
    - 三级联动的数据是全局组件,使用的组件中进行跳转,因为路由跳转的时候,组件会进行销毁的【home组件的created:在向vuex派发action,因此频繁的获取三级联动的数据】
    - 只需要发一次请求,获取到三级联动的数据即可,不需要多次。
    - 最终解决方案:在App中的moutend只会执行一次
APP文件
  mounted(){
    // TypeNav向仓库派发行为 获取数据
    // 放到这里,只需进行一次请求,Home小仓库获得数据后,全局组件TypeNav都会存储到Home小仓库获得的这个数据
    this.$store.dispatch("categroylist");
  },

main虽然也是执行一次,但是它不是组件,没有this,组件才有$store属性

3.路由传递参数先关面试题

 1:路由传递参数(对象写法)path是否可以结合params参数一起使用?
 不可以:不能这样书写,程序会崩掉
 2:如何指定params参数可传可不传?
 3:params参数可以传递也可以不传递,但是如果传递是空串,如何解决?
 4:如果指定name与params配置, 但params中数据是一个"", 无法跳转,路径会出问题
 5: 路由组件能不能传递props数据?

4.axios二次封装

好处:

  • api统一管理,不管接口有多少,所有的接口都可以非常清晰,容易维护.
// 这个文件进行统一的API管理
// 引入axios
import requests from './request'
// 引入mockAjax
import mockrequest from './mockAjax'


// 三级联动的接口
// 这里设置一个函数对外暴露,外面若需要发起三级联动的数据请求调用即可 记住要给函数返回,不然无返回值默认undefined
export const reqCategoryList = ()=>{
    // 发请求成功返回的是promise对象  直接使用封装好的axios
    return requests({
        url:'/product/getBaseCategoryList',
        method:'get'
    })

}

// 获取首页banner(首页轮播图的数据)
export const reqGetBannerList = ()=>mockrequest.get('/banner')
    
//获取floor的数据
export const reqGetFloor = ()=>mockrequest.get('/floor')

// 获取search的数据   这个函数需要不需要外部传递的参数?要给服务器带参进行params给服务器传递参数 调这个函数得有相应的参数     错错错需要接收home页传递过来的params数据和query数据/api/list
// 当前这个接口。给服务器发请求的时候,至少得是一个空对象
export const reqGetSearchInfo = (params)=>requests({
    url:'/list',
    method:'post',
    data:params
})
  • 请求拦截器和响应拦截器
  • nprogress进度条
// 这里进行axios的二次封装
// 主要想用请求拦截器和响应拦截器
import axios from 'axios'
// 引入进度条 start开始 end结束
import nprogress from 'nprogress'
// 引入进度条样式
import "nprogress/nprogress.css"

// 1.利用axios的create方法创建一个axios实例
// 2.request其实就是axios,只不过我们又进行了配置和封装
const requests = axios.create({
    // create里面可以传配置对象

    // 配置对象
    // 基础路径:baseURL就是给每个请求的路径上自动加上所配置的,就不用自己再去书写
    baseURL: '/api',
    // 请求超时的时间
    timeout: 5000
})

// 3.设置请求拦截器,在发请求之前,请求拦截器可以监测到,可以在请求发出去之前做一些事情
requests.interceptors.request.use((config) => {
    // config其实是一个配置对象,里面有属性headers请求头

    // 进度条开始
    nprogress.start()
    return config
});

//4.设置响应拦截器,里面传入成功的回调和失败的回调
requests.interceptors.response.use((response)=>{
    // 成功的回调函数,服务器在响应数据成功的时候,响应拦截器可以检测得到,做一些事情
    // 进度条结束
    nprogress.done()

    // 返回data字段  
    return response.data
},(error)=>{
    // 服务器响应失败回调函数
    // 终结promise
    return Promise.reject(new Error('false'))
})
// 对外暴露
export default requests

5.函数防抖与节流面试题

正常:事件触发非常频繁,而且每一次的触发,回调函数都要去执行(如果时间很短,而回调函数内部有计算,那么很可能出现浏览器卡顿)

防抖:前面的所有的触发都被取消,最后一次执行在规定的时间之后才会触发,也就是说如果连续快速的触发,只会执行最后一次

 <button>点击</button>
    <script>
        // 防抖
        const btn = document.querySelector('button')
        // 事件处理函数
        function pay() {
            console.log("已经购买");
            // 没有处理过就是指向window 正常是button
            console.log(this);
        }
        // 防抖函数
        function debounce(func, delay) { 
            // 3.只创建了一次,是唯一的只不过不断的给timer赋值进行延时而已
            // 每个清除延时就是清除上一个定义的延时,而不是清除新建立的延时
        let timer
            // 因为要在防抖函数里面执行原来的事件处理函数,所以要接收参数来接收,并且去执行这个函数的参数(事件处理函数)
            // 1.一旦监听到了函数就会马上执行,因为要进行处理,使用高阶函数(函数返回函数)
            return function () {
                // 因为在防抖函数里面的定时器里面的this是指向全局变量window的所以要提前保存this
                let This = this
                let arg= arguments
                //    这里虽然提前声明且清除函数调用函数了,但是每个防抖函数都是独立的没有相互联系,因此要使用作用域链(闭包)将声明放在外面
                // let timer
                // 设置清除延时
                // 2.不能清除一个没有定义的变量名,因此将变量名提前声明
                clearTimeout(timer)
                timer = setTimeout(function () {
                    // 通过call方法进行绑定这个this给
                    // func.call(This)
                    // 因为后续可能给事件处理函数传参因此使用apply
                    func.apply(This,arg)
                }, delay)
            }
        }
        btn.addEventListener('click', debounce(pay, 1000))
        // 节流
    </script>

节流:在规定的间隔时间范围内不会重复触发回调,只有大于这个时间间隔才会触发回调,把频繁触发变为少量触发

 <script>
        const btn = document.querySelector('button')
        function pay() {
            console.log("已经购买");
            console.log(this);
        }
        // 节流函数
        function throtte(func, delay) {
            // 节流核心是如果timer被赋值了(有定时在就不进行操作,如果没有赋值就执行任务)
            let timer
            return function () {
                let This = this
                let arg= arguments
                if(timer){
                    return;
                }
                timer = setTimeout(function () {
                    func.apply(This,arg)
                    // 等时间过去,不用清除定时,直接情况timer的值即可
                    // 因为这个清空是在延迟执行任务以后发生
                    timer = null
                }, delay)
            }
        }
        btn.addEventListener('click', throtte(pay, 1000))
    </script>
    方法二
     <script>
         const btn = document.querySelector('button')
        function pay() {
            console.log("已经购买");
            console.log(this);
        }
        // 节流函数
        function throtte(func, delay) {
            // 节流核心是如果timer被赋值了(有定时在就不进行操作,如果没有赋值就执行任务)
            let pre = 0;
            return function () {
                let This = this
                let arg= arguments
                let now = new Date()
              if(now - pre>dalay){
                fun.apply(This.arg);
                pre = now;
              }
            }
        }
        btn.addEventListener('click', throtte(pay, 1000))
    </script>

6.路由的跳转与传参

1.第一种声明式导航:为什么使用router-link组件的时候,会出现卡顿那?
router-link是一个组件:相当于VueComponent类的实例对象,一瞬间
new VueComponent很多实例(1000+),很消耗内存,因此导致卡顿。
{{ c1.categoryName }}

2.第二种编程式导航:push|replace

三级分类由于使用router-link的时候,会出现卡顿现象,因此采用编程式导航。
因为是有很多的级联,v-for循环得到的,因此在循环过程中,回调函数也会依次增加
优化:编程式导航+事件委派的冒泡原理将绑定一个回调函数,则会相应的隐射到每一个子节点

路由跳转的时候【home->search】:需要进行路由传递参数【分类的名字、一、二、三级分类的id】

this.$router.push()
{
 name:'search',
 query:{
    categoryName:'电子书',
    category2Id:4
 }
}
// 三级联动路由跳转和传递参数的业务
    goSearch(event) {
      // alert(444)
      // 问题1:如何判断点击子节点的是A标签
      // 答:把子节点当中的a标签,加上自定义的属性,其余子节点是没有的(自定义属性:浏览器会将驼峰命名转换为一般的命名)
      // 问题2:如何判断是几级的目录?
      // 答:也是根据自定义属性加上的自身的ID值进行条件判断
      // 问题3:如何获取当前的事件 答:event

      // event.target :获取到的是触发事件的元素(h3,a,dt,dl)
      let node = event.target;
      // 节点有一个属性dataset属性,可以获取自定义属性与属性值 (这里一定要小写,不是给你说了么,浏览器会将自定义属性变为全部小写)
      let { categoryname, category1id, category2id, category3id } =
        node.dataset;
      console.log(event);
      // 当这个标签是A标签的时候才会进入判断
      if (categoryname) {
        /*         {
        name:'search',
        query:{
            categoryName:'电子书',
            category2Id:4
        } */
        // 准备路由跳转的参数 设置对象
        let location = { name: "search" };
        let query = { categoryname: categoryname };
        // 一级目录
        if (category1id) {
          query.category1id = category1id;
        } else if (category2id) {
          query.category2Id = category2id;
        } else {
          query.category3id = category3id;
        }

        // 路由跳转前要合并参数
        // 1.判断路由中是否有params参数,有则进行合并
        if (this.$route.params) {
          // 动态的给location添加params属性
          location.params = this.$route.params;
          // 动态的给location添加query属性
          location.query = query;
        }
        this.$router.push(location);
      }
    },

7.搜索模块中的三级联动与过渡动画

在home模块当中,使用了一个功能三级联动功能---->[typeNav]
在search模块当中,也使用三级联动的功能------->[typeNav]

TypeNav组件业务分析?

  • 三级联动在home模块正常显示
  • 三级联动在search一会显示、一会隐藏 —解决方案:通过一个响应式属性控制三级联动显示与隐藏
    说白了:你需要让三级联动组件知道谁在用它。
  • 通过 r o u t e 让组件区分在那个模块下解决办法: 1. T y p e N a v 组件添加 v − s h o w 进行动态绑定 2. d a t a 方法中设置 s h o w 的初始值 3. 通过 route让组件区分在那个模块下 解决办法: 1.TypeNav组件添加v-show进行动态绑定 2.data方法中设置 show的初始值 3.通过 route让组件区分在那个模块下解决办法:1.TypeNav组件添加vshow进行动态绑定2.data方法中设置show的初始值3.通过route路由信息区分
    // 当鼠标移入时,全部商品分类列表进行展示
    enterShow() {
      if (this.$route.path != "/home") {
        this.show = true;
      }
    },
    // 当鼠标离开的时候,全部商品类别进行影藏
    leaveShow() {
      if (this.$route.path != "/home") {
        this.show = false;
      }
  • 路由跳转的时候,相应的组件会把重新销毁与创建----【kepp-alive】

4)过渡效果

  • 最早接触的时候:CSS3
  • Vue当中也有过渡动画效果—transition内置组件完成
 HTML<transition name="sort"> 相应的节点和组件</transition>
 CSS// 过渡动画的样式
    // 开始进入状态
    .sort-enter {
      height: 0;
    }
    // 结束状态
    .sort-enter-to {
      height: 461px;
    }
    // 定义动画的时间和速率
    .sort-enter-active {
      transition: all 0.5s linear;
    }
  • 注意1,在Vue当中,你可以给 (某一个节点)|(某一个组件)添加过渡动画效果
  • 节点|组件务必出现v-if|v-show指令才可以使用。

8.为什么会频繁的向服务器发请求获取三级联动的数据那?

  • 三级联动的数据是全局组件,使用的组件中进行跳转,因为路由跳转的时候,组件会进行销毁的【home组件的created:在向vuex派发action,因此频繁的获取三级联动的数据】,只需要发一次请求,获取到三级联动的数据即可,不需要多次。
  • 最终解决方案:在App中的moutend只会执行一次
  • main虽然也是执行一次,但是它不是组件,没有this,组件才有$store属性

9.合并参数

进入搜索页面的时候需要传递各种的参数,从而才能向服务器发请求获得相应的数据

  • 合并参数
    为什么需要合并参数(query|params):因为这些参数,对于search是有用的,因为search通过这些参数
    向服务器发请求,需要把这些参数携带给服务器,服务器就会返回相应的用户的搜索的数据,search就可以进行展示。

1.开发的三级联动业务,当你点击a标签的时候,会进行路由的跳转,将产品的名字与id传递给search模块----(query)
2.点击搜索按钮的时候,用户输入进来的关键字,点击按钮的时候会通过params参数传递给search模块-----(params)
3.路由跳转(home->search),两个地方,三级联动(typeNav)、Header组件(搜索按钮)

 // 路由跳转前要合并参数
        // 1.判断路由中是否有params参数,有则进行合并
        if (this.$route.params) {
          // 动态的给location添加params属性
          location.params = this.$route.params;
          // 动态的给location添加query属性
          location.query = query;
        }
        this.$router.push(location);
      }

9.mock数据

接口没有写好,前端人员可以mock一些数据【前端程序员自己模拟的一些假的接口】,当中工作中项目上线,需要把mock数据变为后台给的接口数据替换。

10.组件间通信

props:父子
插槽:父子
自定义事件:子父
全局事件总线$bus:万能
pubsub:万能
Vuex:万能
$ref:父子通信

11.用户在搜索模块要进行多次请求去渲染相应的数据

开始:放在mouted生命周期钩子里面,只会请求一次
解决办法:watch和路由的$route方法监听路由的信息是否发生变

// 数据监听,监听组件实例身上的属性值发生变化  从而用户可以重复的根据组件身上的数据去重复的发送请求
  watch: {
    // 监听路由的信息是否发生变化
    $route(newValue,oldValue) {
      // 再次向服务器发送请求之前整理数据带给服务器
      Object.assign(this.searchParams,this.$route.params,this.$route.query)
      // console.log(this.searchParams);
      // 再次发送请求 解决只能一次去发送请求
       this.getData();
      //  每一次请求的时候,应该把相应的123级ID清空,让他接收下一次的相应的123ID
      // 分类和关键字不用清理,因为每次路由发生变化的时候,会给他重新赋值
      this.searchParams.category1Id = ''
       this.searchParams.category2Id = ''
       this.searchParams.category3Id = ''
    },
  },

你可能感兴趣的:(vue.js,面试)