面试总结-某治科技

183 阅读7分钟

css定位属性有什么

positon: 属性;

static 静态定位 relative 相对定位, 相对自己原来的位置 absolute 绝对定位, 相对于最近的定位父元素定位 fixed 固定定位, 相对于浏览器窗口进行定位

兼容ie9

没有实际做过

如何做兼容ie9以下浏览器

HTML5兼容

引入html5shiv.js, 解决ie9以下不支持支持HTML5元素

使用IE条件注释, 在<head>标签中引入html5shiv.js

  <head>
      <!-- 省略... -->
    <!--[if lt IE 9]>
      <script src="https://cdn.bootcdn.net/ajax/libs/html5shiv/3.7.3/html5shiv.min.js"></script>
    <![endif]-->
  </head>

IE条件注释说明

<![endif]--> 
<!-- IE条件注释语句
针对的浏览器版本
<!--[if lt IE 7]> 内容 <![endif]--> 
IE7 以下版本 (小于IE7

<!--[if lte IE 7]>内容<![endif]-->
IE7及以下版本 (包含IE7

<!--[if gt IE 7]>内容<![endif]--> 
IE7 以上版本 (大于IE7

<!--[if gte IE 7]>内容<![endif]--> 
IE7及以上版本 (包含IE7

<!--[if !IE 7]>内容<![endif]--> 
非IE7版本

<!--[if !IE]><!--> 
非IE版本

<!--<![endif]--> 

CSS兼容

  • 不同浏览器样式差异 不同浏览器的默认样式存在差异, 可以通过Normalize.css抹平差异,当然也可以根据定制自己的reset.css
<link href="https://cdn.bootcdn.net/ajax/libs/normalize/8.0.1/normalize.min.css" rel="stylesheet">

简单粗暴的方式, 通配符选择器统一修改(不建议, 性能不好)

* { margin: 0; padding: 0; }
  • 对于CSS3属性的兼容 在CSS3没有纳入真正的标准时,浏览器厂商就开始支持这些属性的使用了。 CSS3样式语法还存在波动时,浏览器厂商提供了针对浏览器的前缀,直到现在还是有部分的属性需要加上浏览器前缀。 在开发过程中我们一般通过IDE开发插件、css 预处理器以及前端自动化构建工程帮我们处理。

核心就是添加浏览器前缀

浏览器内核与前缀的对应关系如下

内核 主要代表的浏览器 前缀
Trident IE浏览器 -ms
Gecko Firefox -moz
Presto Opera -o
Webkit Chrome和Safari -webkit
  • 解决IE9以下不能使用透明属性opacity
 opacity: 0.5;
 // IE6-IE8我们习惯使用filter滤镜属性来进行实现
 filter: alpha(opacity = 50);
 // IE4-IE9都支持滤镜写法progid:DXImageTransform.Microsoft.Alpha(Opacity=xx)
 filter: progid:DXImageTransform.Microsoft.Alpha(style = 0, opacity = 50);
  • 媒体查询 解决 ie9 以下浏览器不支持 CSS3 Media Query 的问题, 引入respond.js
<script src="https://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
  • 支持 <picture> 标签 解决 IE 9 10 11 等浏览器不支持 <picture> 标签的问题
<script src="https://cdn.bootcdn.net/ajax/libs/picturefill/3.0.3/picturefill.min.js"></script>

js兼容

  • 事件兼容 封装一个适配器的方法,过滤事件句柄绑定、移除、冒泡阻止以及默认事件行为处理
var eventshiv = {
    // event兼容
    getEvent: function(event) {
        return event ? event : window.event;
    },

    // type兼容
    getType: function(event) {
        return event.type;
    },

    // target兼容
    getTarget: function(event) {
        return event.target ? event.target : event.srcelem;
    },

    // 添加事件句柄
    addHandler: function(elem, type, listener) {
        if (elem.addEventListener) {
            elem.addEventListener(type, listener, false);
        } else if (elem.attachEvent) {
            elem.attachEvent('on' + type, listener);
        } else {
            // 在这里由于.与'on'字符串不能链接,只能用 []
            elem['on' + type] = listener;
        }
    },

    // 移除事件句柄
    removeHandler: function(elem, type, listener) {
        if (elem.removeEventListener) {
            elem.removeEventListener(type, listener, false);
        } else if (elem.detachEvent) {
            elem.detachEvent('on' + type, listener);
        } else {
            elem['on' + type] = null;
        }
    },

    // 添加事件代理
    addAgent: function (elem, type, agent, listener) {
        elem.addEventListener(type, function (e) {
            if (e.target.matches(agent)) {
                listener.call(e.target, e); // this 指向 e.target
            }
        });
    },

    // 取消默认行为
    preventDefault: function(event) {
        if (event.preventDefault) {
            event.preventDefault();
        } else {
            event.returnValue = false;
        }
    },

    // 阻止事件冒泡
    stopPropagation: function(event) {
        if (event.stopPropagation) {
            event.stopPropagation();
        } else {
            event.cancelBubble = true;
        }
    }
};
  • 参考

水平垂直居中

  • flex
  #box {
    display: flex;
    justify-content: center;
    align-items: center;
  }
  • 绝对定位加transform
    div{
        width: 200px;
        height: 200px;
        background: green;

        position: absolute;
        left: 50%;    /* 放到定位父级的50%位置 */
        top: 50%;
        transform: translate(-50%, -50%); /*自己的-50% */
    }
  • 绝对定位加margin:auto
    div{
        width: 200px;
        height: 200px;
        background: green;

        position:absolute;
        left:0;
        top: 0;
        bottom: 0;
        right: 0;
        margin: auto;
    }
  • 绝对定位加上负margin
    div{
        width: 200px;
        height: 200px;
        background: green;
        
        position: absolute;
        left: 50%;
        top: 50%;
        margin-left: -100px;
        margin-top: -100px;
    }
  • table-cell
    display: table-cell;
    text-align: center;
    vertical-align: middle;

js中数据类型

6中基本数据类型

  • number
  • string
  • boolean
  • null
  • undefined
  • symbol

null和undefined比较

null == undefined 值都是空值, 为true null === undefined 值相等但是数据类型不同, 为false

typeof null和typeof undefined

typeof undefined是"undefined"

typeof null是object,JS 存在的一个Bug。在 JS 的最初版本中使用的是 32 位系统,为了性能考虑使用低位存储变量的类型信息,000开头代表是对象, 然而 null使用全零进行表示,所以将它错误的判断为 object

js的同步和异步(Eventloop)

  1. js是单线程的
  2. 同步: 函数执行后, 会函数执行完毕后, 会马上获得执行结果
  3. 异步: 函数执行后, 函数马上返回, 但是不会马上返回预期结果, 需要等待一段时间, 返回结果后通过回调的方式获得结果

event loop它的执行顺序:

  • 一开始script整个脚本作为一个宏任务执行
  • 执行过程中同步代码直接执行,宏任务进入宏任务队列,微任务进入微任务队列
  • 当前宏任务执行完出队,检查微任务列表,有则依次执行,直到全部执行完
  • 执行浏览器UI线程的渲染工作
  • 检查是否有Web Worker任务,有则执行
  • 执行完本轮的宏任务,回到2,依此循环,直到宏任务和微任务队列都为空

微任务包括:MutationObserverPromise.then()或catch()Promise为基础开发的其它技术,比如fetch APIV8的垃圾回收过程、Node独有的process.nextTick

宏任务包括scriptsetTimeoutsetIntervalsetImmediateI/OUI rendering

注意⚠️:在所有任务开始的时候,由于宏任务中包括了script,所以浏览器会先执行一个宏任务,在这个过程中你看到的延迟任务(例如setTimeout)将被放到下一轮宏任务中来执行。

  • 参考

setTimeout的代码一定的按时执行吗

setTimeout的运行机制:执行到该语句时,是立即把当前定时器代码推入事件队列,当定时器在事件列表满足设置的时间值时将传入的函数加入任务队列,之后的执行就交给任务队列负责。 但是如果此时任务队列不为空,则需等待,所以执行定时器内代码的时间可能会大于设置的时间

说了一下它属于异步任务,然后说了一下还有哪些宏任务以及微任务,最后说了一下EventLoop的执行过程。

  • 一开始整个脚本作为一个宏任务执行

  • 执行过程中同步代码直接执行,宏任务进入宏任务队列,微任务进入微任务队列

  • 当前宏任务执行完出队,检查微任务列表,有则依次执行,直到全部执行完

  • 执行浏览器UI线程的渲染工作

  • 检查是否有Web Worker任务,有则执行

  • 执行完本轮的宏任务,回到2,依此循环,直到宏任务和微任务队列都为空

vue组件通信

父组件给子组件传值

使用props,父组件可以使用props向子组件传递数据

例子 父组件Father.vue

<template>
  <div>
    <son :msg="msg" />
  </div>
</template>

<script>
import Son from './Son'

export default {
  components: { Son },
  data() {
    return {
      msg: 'this is Father'
    }
  }
}
</script>

子组件Son.vue

<template>
  <div>
    <p>{{ msg }}</p>
  </div>
</template>

<script>

export default {
  props: {
    msg: {
      type: String,
      required: true
    }
  }
}
</script>

子组件给父组件传值

父组件向子组件传递事件方法,子组件通过$emit触发事件,回调给父组件

父组件Father.vue

<template>
  <div>
    <son :msg="msg" @updateMessage="handleChangeMsg" />
  </div>
</template>

<script>
import Son from './Son'

export default {
  components: { Son },
  data() {
    return {
      msg: 'this is Father'
    }
  },
  methods: {
    handleChangeMsg(obj) {
      console.log(obj) // { time: "2020/5/12 下午8:48:17" }
      this.msg = this.msg + ' abc'
    }
  }
}
</script>

子组件Son.vue

<template>
  <div>
    <p>{{ msg }}</p>
    <p>
      <button @click="updateMsg">点击更新</button>
    </p>
  </div>
</template>

<script>

export default {
  props: {
    msg: {
      type: String,
      required: true
    }
  },
  methods: {
    updateMsg() {
      this.$emit('updateMessage', { time: new Date().toLocaleString() })
    }
  }
}
</script>

非父子,兄弟组件之间通信

可以通过实例一个vue实例Bus作为媒介,要相互通信的兄弟组件之中,都引入Bus,然后通过分别调用Bus事件触发和监听来实现通信和参数传递

  • 定义公共事件Bus.js
    import Vue from 'vue'
    export default new Vue()

需要通信的组件都需要引入同一个Bus.js 派发事件方使用Bus.$emit派发事件, 接收事件方需要在钩子函数中监听事件(最好是created中)

  • A组件中 引入Bus.js, 使用Bus.$emit派发事件
<template>
    <button @click="toBus">子组件传给兄弟组件</button>
</template>

<script>
import Bus from '../common/js/bus.js'
export default{
    methods: {
        toBus () {
            Bus.$emit('on', '来自兄弟组件')
        }
      }
}
</script>
  • B组件中 引入Bus.js, 在钩子函数中监听on事件
import Bus from '../common/js/bus.js'
export default {
    data() {
      return {
        message: ''
      }
    },
    mounted() {
       Bus.$on('on', (msg) => {
         this.message = msg
       })
     }
   }

  • 依赖注入provide+inject 参考elementui的forminput组件

  • 组件的ref属性 拿到组件实例, 可以直接调用组件的数据和方法

双向数据绑定原理

通过数据劫持和发布订阅模式结合

父组件拿到子组件的属性和方法

组件的ref属性