rem与em区别
在css中单位长度用的最多的是px、em、rem,这三个的区别是:
- px是固定的像素,一旦设置了就无法因为适应页面大小而改变。
- em和rem相对于px更具有灵活性,他们是相对长度单位,意思是长度不是定死了的,更适用于响应式布局。
- 对于em和rem的区别一句话概括:em相对于父元素,rem相对于根元素。
- rem中的r意思是root(根源),这也就不难理解了
em
- 子元素字体大小的em是相对于父元素字体大小
- 元素的width/height/padding/margin用em的话是相对于该元素的font-size
<div>我是父元素div<p>我是子元素p<span>我是孙元素span</span></p>
</div>
div {font-size: 40px;width: 10em; /* 400px */height: 10em;border: solid 1px black;
}
p {font-size: 0.5em; /* 20px */ width: 10em; /* 200px */height: 10em;border: solid 1px red;
}
span {font-size: 0.5em; width: 10em;height: 10em;border: solid 1px blue;display: block;
}
巩固测验:你能说出孙元素span的font-size和width吗?
答案:我猜你会说10px、100px,哈哈,其实逻辑上是正确的,但是如果你是chrome浏览器我不得不告诉你应该是12px、120px。因为chrome设置的最小
字体大小为12px,意思就是说低于12px的字体大小会被默认为12px,当然这一尬境可以由css3解决,这里就不多说了。
chrome默认的字体大小是12px,也就是1em默认为12px,如果最外层的父元素直接把font-size设为1.5em,那么该元素的字体大小为18px(12*1.5)。
rem
rem是全部的长度都相对于根元素,根元素是谁?<html>元素。通常做法是给html元素设置一个字体大小,然后其他元素的长度单位就为rem。
html {font-size: 10px;}
div {font-size: 4rem; /* 40px */width: 30rem; /* 300px */height: 30rem;border: solid 1px black;
}
p {font-size: 2rem; /* 20px */width: 15rem;height: 15rem;border: solid 1px red;
}
span {font-size: 1.5rem;width: 10rem;height: 10rem;border: solid 1px blue;display: block;
}
Vue Set基本用法与使用场景
- 基本用法
Vue.set( target, propertyName/index, value )
参数:
{Object | Array} target
{string | number} propertyName/index
{any} value
返回值:设置的值。
var vm =new Vue({el:'#app',data:{items:['a', 'b', 'c']},methods:{btn(){Vue.set(this.items, 1, 'e')console.log(this.items)}}
})
- 使用场景
只有先定义在data 里 数据才具有响应式,如果自己后添加的属性是不具备响应式的。
场景1:通过数组的下标去修改数组的值,数据已经被修改了,但是不触发updated函数,视图不更新。
data () {return {items: ['a', 'b', 'c']};},
methods: {changeItem2 () {this.$set(this.items, 0, 'x');console.log(222, this.items[0]);},
}
场景2: vue中检测不到对象属性的添加和删除。
data() {userProfile: {name: '小明',}
}
addProperty () {this.$set(this.userProfile, 'age', '12');// { name: '小明', age: '12'}}
简单的解释一下原理:
vue在创建实例的时候把data深度遍历所有属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter。让 Vue 追踪依赖,在属性被访问和修改时通知变化。所以属性必须在 data 对象上存在才能让 Vue 转换它,这样才能让它是响应的。
当你在对象上新加了一个属性 newProperty,当前新加的这个属性并没有加入vue检测数据更新的机制(因为是在初始化之后添加的),vue.$set是能让vue知道你添加了属性, 它会给你做处理。
手写call、apply、bind方法
- call和apply实现思路主要是:
- 判断是否是函数调用,若非函数调用抛异常
- 通过新对象(context)来调用函数
- 给context创建一个
fn
设置为需要调用的函数 - 结束调用完之后删除
fn
- 给context创建一个
- bind实现思路
- 判断是否是函数调用,若非函数调用抛异常
- 返回函数
- 判断函数的调用方式,是否是被new出来的
- new出来的话返回空对象,但是实例的
__proto__
指向_this
的prototype
- new出来的话返回空对象,但是实例的
- 判断函数的调用方式,是否是被new出来的
- 完成函数柯里化
Array.prototype.slice.call()
- call
Function.prototype.myCall = function (context) {// 先判断调用myCall是不是一个函数// 这里的this就是调用myCall的if (typeof this !== 'function') {throw new TypeError("Not a Function")}// 不传参数默认为windowcontext = context || window// 保存thiscontext.fn = this// 保存参数let args = Array.from(arguments).slice(1) //Array.from 把伪数组对象转为数组// 调用函数let result = context.fn(...args)delete context.fnreturn result}
- apply
Function.prototype.myApply = function (context) {// 判断this是不是函数if (typeof this !== "function") {throw new TypeError("Not a Function")}let result// 默认是windowcontext = context || window// 保存thiscontext.fn = this// 是否传参if (arguments[1]) {result = context.fn(...arguments[1])} else {result = context.fn()}delete context.fnreturn result}
- bind
Function.prototype.myApply = function (context) {// 判断this是不是函数if (typeof this !== "function") {throw new TypeError("Not a Function")}let result// 默认是windowcontext = context || window// 保存thiscontext.fn = this// 是否传参if (arguments[1]) {result = context.fn(...arguments[1])} else {result = context.fn()}delete context.fnreturn result}