面试题整理
数组篇
数组去重有哪些方法,那原生js使用for循环如何实现的
1.利用ES6中的 Set 方法去重 ( Array.from是将set对象转为数组)
1 let arr = [1,0,0,2,9,8,3,1];
2 function unique(arr) {
3 return Array.from(new Set(arr))
4 }
5 console.log(unique(arr)); // [1,0,2,9,8,3]
or
6 console.log(...new Set(arr)); // [1,0,2,9,8,3]
2.利用数组的indexOf方法去重
注:array.indexOf(item,statt) 返回数组中某个指定的元素的位置,没有则返回-1
1 var arr =[1,-5,-4,0,-4,7,7,3];
2 function unique(arr){
3 var arr1 = []; // 新建一个数组来存放arr中的值
4 for(var i=0,len=arr.length;i<len;i++){
5 if(arr1.indexOf(arr[i]) === -1){
6 arr1.push(arr[i]);
7 }
8 }
9 return arr1;
10 }
11 console.log(unique(arr)); // 1, -5, -4, 0, 7, 3
3.利用数组的sort方法去重(相邻元素对比法)
注:array.sort( function ) 参数必须是函数,可选,默认升序
var arr = [5,7,1,8,1,8,3,4,9,7];
function unique( arr ){
arr = arr.sort();
console.log(arr);
var arr1 = [arr[0]];
for(var i=1,len=arr.length;i<len;i++){
if(arr[i] !== arr[i-1]){
arr1.push(arr[i]);
}
}
return arr1;
}
console.log(unique(arr))l; // 1, 1, 3, 4, 5, 7, 7, 8, 8, 9
4.利用数组的includes去重
注:arr.includes(指定元素(必填),指定索引值(可选,默认值为0) ),有值返回true,没有则返回false
1 var arr = [-1,0,8,-3,-1,5,5,7];
2 function unique( arr ){
3 var arr1 = [];
4 for(var i=0,len=arr.length;i<len;i++){
5 if( !arr1.includes( arr[i] ) ){ // 检索arr1中是否含有arr中的值
6 arr1.push(arr[i]);
7 }
8 }
9 return arr1;
10 }
11 console.log(unique(arr)); // -1, 0, 8, -3, 5, 7
5.利用数组的filter方法去重
注:filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素,array.filter(function(currentValue,index,arr), thisValue)
currentValue:当前元素的值(必选参数)、index:当前元素的索引值(可选)、arr:当前元素属于的数组对象(可选)、thisValue:对象作为该执行回调时使用,传递给函数,用作 "this" 的值,默认undefined(可选)
1 var arr = [1,2,8,9,5,8,4,0,4];
2 /*
3 模拟: 原始数组:[1,2,8,9,5,8,4,0,4]
4 索引值:0,1,2,3,4,5,6,7,8
5 伪新数组:[1,2,8,9,5,8,4,0,4]
6 使用indexOf方法找到数组中的元素在元素在中第一次出现的索引值
7 索引值:0,1,2,3,4,2,6,7,6
8 返回前后索引值相同的元素:
9 新数组:[1,2,8,9,5,4,0]
10 */
11 function unique( arr ){
12 // 如果新数组的当前元素的索引值 == 该元素在原始数组中的第一个索引,则返回当前元素
13 return arr.filter(function(item,index){
14 return arr.indexOf(item,0) === index;
15 });
16 }
17 console.log(unique(arr)); // 1, 2, 8, 9, 5, 4, 0
6.利用函数递归去重
1 var arr = [1,1,5,6,0,9,3,0,6]
2 function unique( arr ){
3 var arr1 = arr;
4 var len = arr1.length;
5 arr1.sort((a,b)=>{
6 return a-b
7 })
8 function loop(index){
9 if(index >= 1){
10 if(arr1[index] === arr1[index-1] ){
11 arr1.splice(index,1);
12 }
13 loop(index - 1); // 递归loop,然后数组去重
14 }
15 }
16 loop(len-1);
17 return arr1
18 }
19 console.log(unique(arr)); // 0, 1, 3, 5, 6, 9
7.利用ES6中的Map方法去重
1 /*
2 创建一个空Map数据结构,遍历需要去重的数组,把数组的每一个元素作为key存到Map中。由于Map中不会出现相同的key值,所以最终得到的就是去重后的结果。
3 */
4 let arr = [1, 0, 8, 3, -9, 1, 0, -9, 7]
5 function unique(arr) {
6 let map = new Map();
7 console.log(map)
8 //let arr1 = new Array(); // 数组用于返回结果
9 let arr1 = []
10 for (let i = 0, len = arr.length; i < len; i++) {
11 if (map.has(arr[i])) { // 判断是否存在该key值
12 map.set(arr[i], true);
13 }
14 else {
15 map.set(arr[i], false);
16 arr1.push(arr[i]);
17 }
18 }
19 return arr1;
20 }
21 console.log(unique(arr)); // 1, 0, 8, 3, -9, 7
8.双重for循环+splice()
let arr = [1, 5, 3, 3, 5]
for (let i = 0; i < arr.length; i++) {
for (let j = i + 1; j < i + arr.length; j++) {
if (arr[i] === arr[j]) {
// 第一个等同于第二个,splice方法删除第二个
arr.splice(j, 1)
j--
}
}
}
console.log(arr); // [1, 5, 3]
9.js双重for循环
var arr=[1,2,2,3,5,4,5]
let result=[]
for(let i=0;i<arr.length;i++){
// console.log(i); 每个数的下标
for(var j=0;j<result.length;j++){
// 如果arr的下标的数与result的数相等,那就退出循环
if(arr[i]===result[j]){
break
}
}
console.log(j);
// 如果j===result.length相等,就把对应的元素添加到result数组里
if(j===result.length){
result.push(arr[i])
}
}
console.log(result); // [ 1, 2, 3, 5, 4 ]
Set / Map的区别
Set类似于数组,但是它里面每一项的值是唯一的,没有重复的值,Set是一个构造函数,用来生成set的数据结构 .数组去重(利用扩展运算符)
Map对象保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值。构造函数Map可以接受一个数组作为参数,数组的成员是一个个表示键值对的数组。注意Map里面也不可以放重复的项。
综上所述,主要有一下几个区别:
1.Map是键值对,Set是值的集合,当然键和值可以是任何的值;
2.Map可以通过get方法获取值,而set不能因为它只有值;
3.都能通过迭代器进行for…of遍历;
4.Set的值是唯一的可以做数组去重,Map由于没有格式限制,可以做数据存储
5.map和set都是stl中的关联容器,map以键值对的形式存储,key=value组成pair,是一组映射关系。set只有值,可以认为只有一个数据,并且set中元素不可以重复且自动排序。
ES6的理解
0.ES6是ECMAScript 6的缩写简称,2015 年 6 月,ECMAScript 6 正式通过,
1.变量声明let与const (1).变量不会提升 (2).有块级作用域
2.解构赋值语法 : 其实就是变量赋值语法的简写形式 (取出 对象的属性 赋值 给变量)
3.箭头函数 其实是 function 关键字的简写形式
4.拓展运算符: ... ( 作用:类似于 对象遍历的一种简写形式 )
5.数组迭代方法
数组排序
1.sort()
:对数组的元素进行从小到大来排序(会改变原来的数组) 默认排序顺序是在将元素转换为字符串按照Unicode 编码,从小到大进行排序
//一维数组排序
var arr=[1,5,7,9,16,2,4];
arr.sort(function(a,b){
return b-a; //降序排列,return a-b; —>升序排列
}) //括号里不写回调函数,则默认按照字母逐位升序排列,结果为[1,16,2,4,5,7,9]
2.冒泡排序(每一趟找出最大的)
两个相邻的数比较大小,将两个数中较大的数往右边放,小的往左边放
//性能一般
let arr=[1,5,7,9,16,2,4];
//冒泡排序,每一趟找出最大的,总共比较次数为arr.length-1次,每次的比较次数为arr.length-1次,依次递减
let len = arr.length;
for(let k = 0; k < len - 1; k++) {
for(let m = 0; m < len - k - 1; m++) {
if(arr[m] > arr[m+1]){
let val = arr[m];
arr[m] = arr[m+1];
arr[m+1] = val;
}
}
}
console.log(arr)
3.插入排序
var arr=[45,1,32,21,56,87,43,12,34,45];
for(var i=0;i<arr.length;i++){
var n=i;
while(arr[n]>arr[n+1] && n>=0){
var temp=arr[n];
arr[n]=arr[n+1];
arr[n+1]=temp;
n--;
}
}
4.希尔排序(性能最好的排序)
function xier(arr){
var interval = parseInt(arr.length / 2); //分组间隔设置
while(interval > 0){
for(var i = 0 ; i < arr.length ; i ++){
var n = i;
while(arr[n] < arr[n - interval] && n > 0){
var temp = arr[n];
arr[n] = arr[n - interval];
arr[n - interval] = temp;
n = n - interval;
}
}
interval = parseInt(interval / 2);
}
return arr;
}
xier([12,9,38,44,7,98,35,59,49,88,38]);
数组合并说出最少三种方法
1.es6 利用 展开运算符 “…”
2.利用 数组方法 concat,合并两个或多个数组 (会造成内存浪费,不能处理嵌套数组) **
改变原数组
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
arr1 = arr1.concat(arr2)
不改变原数组
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
var arr3 = arr1.concat(arr2)
使用扩展操作符或array.concat()执行的合并将创建一个新数组。但是,有时不想创建一个新数组,而是想将它合并到一些现有的数组中。下面的方法执行一种可变的合并方法。
3.使用array.push()方法进行合并
array.push(item)
方法将一个项加入到数组的末尾,改变了调用该方法的数组:
const heroes = ['Batman'];
heroes.push('Superman');
heroes; // ['Batman', 'Superman']
数组 push ,pop , map, unshift?
1.push: 数组尾部添加 push() 方法可向数组的末尾添加一个或多个元素,并返回新的长度
2.pop:数组尾部删除 pop() 方法用于删除并返回数组的最后一个元素
3.unshift:数组头部添加 unshift() 方法可向数组的开头添加一个或更多元素,并返回新的长度
4.map:map()方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。
vue篇
Vue2 中 v-for 和 v-if 为什么不建议放一行?为什么?怎么处理?Vue3 呢
官网回答:vuejs.bootcss.com/style-guide…
为什么
:当 Vue 处理指令时,v-for
比 v-if
具有更高的优先级,这意味着 v-if 将分别重复运行于 每个 v-for 循环中,即先运行 v-for 的循环,然后在每一个 v-for 的循环中,再进行 v-if 的条件对比,而v-if是通过创建和销毁dom元素来控制元素的显示与隐藏,所以就会不停的去创建和销毁元素,会造成性能问题,影响速度
处理
: 为了避免这个问题,可以用计算属性代替.样只会在users发生改变时才会执行这段遍历的逻辑,和之前相比,避免了不必要的性能浪费。( 或者:在v-for的外层或内层包裹一个元素来使用v-if ) 如果条件出现再循环内部,可通过计算属性 computed 提前过滤掉那些不需要显示的项
好处
: 过滤后的列表只会在 users 数组发生相关变化时才被重新运算,过滤更高效。
使用 v-for="user in activeUsers" 之后,我们在渲染的时候只遍历活跃用户,渲染更高效。
解耦渲染层的逻辑,可维护性 (对逻辑的更改和扩展) 更强。
vue3
: vue3中v-if的优先级高于v-for,如果写在同一个标签中会先使用v-if,而v-if的数据来自v-for的循环子项会导致出错,因为数据还未声明.
Vue 中的 data 为什么要求是一个函数?
多个组件复用时,每次调用data函数的时候都会return一个新的对象,它们的内存地址都是不一样的,这样就不会相互影响。为了保证组件的独立性和可复用性
computed 和 watch 的区别
computed
:计算属性为了简化计算复杂度,具有缓存,不能执行异步代码,必须同步执行,适用于计算比较消耗性能的计算场景、必须要有一个返回值
watch
: 侦听器,检测属性值,只要属性值改变,就会触发监听。
echarts怎么挂载
一、安装并全局引入
1、通过npm获取echarts
npm install echarts --save
2、在 main.js 中全局配置
首先在main.js中引入echarts,将其绑定到vue原型上:
import echarts from 'echarts'
Vue.prototype.$echarts = echarts;
3.创建一个dom容器
<div id="main" style="width: 750px; height: 400px"></div>
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById("main"));
组件传值
1.父子组件传值:
父--->子 : 通过props 传递,子组件接收
子---->父 : 通过一个自定义事件,然后this.$emit传递给父组件
2.兄弟组件传值
: eventBus事件总线
在全局挂载enentBus,创建一个谁都能找到的事件总线, 通过$emit 和 $on
进行传递和接收。
- 后代组件传值 :
通过provide 和 inject
。爷爷定义一个属性 provide,是一个函数,用来给后代接收。 孙子用 inject 接收。
组件缓存
keep-alive:
语法:两个属性: include 和 exclude
1.先给对应组件设置name属性名,
2.再把名字写到 include/exclude位置
include==包含--缓存
exclude==不包含--不缓存
js篇
闭包
闭包(closure):指有权访问另外一个函数作用域中的变量的函数。简单的说就是,一个作用域可以访问另外一个函数内部的局部变量。函数
+上下文
function fn() {
var num = 10;
function fun() {
console.log(num);
}
return fun;
}
var f = fn();
f();
作用:延长变量作用域、在函数的外部可以访问函数内部的局部变量,容易造成内层泄露,因为闭包中的局部变量永远不会被回收. 在实际开发中,闭包最大的作用就是用来 变量私有。
深拷贝,浅拷贝
浅拷贝:基本数据类型拷贝的值,引用数据类型拷贝的是内存地址。原对象和拷贝对象还是会互相影响。两个对象指向同一内存地址。
如何实现:1.Object.assign
2.数组的 slice 和 concat 方法 Array.prototype.concat()
,Array.prototype.slice()
3.扩展运算符
4.函数库Lodash的_.clone方法
深拷贝:深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存,拷贝前后两个对象互不影响
如何实现:
1.一行代码: 用 JSON.stringify 把对象转换成字符串,再用 JSON.parse 把字符串转换成新的对象。 但是这种方式存在弊端,会忽略undefined
、symbol
和函数
;NaN
、Infinity
、-Infinity
会被序列化为 null
;
const newObj = JSON.parse(JSON.stringify(obj))
- Lodash.cloneDeep 实现深拷贝
- 使用递归的方式实现深拷贝
作用域
作用域链
js 在执⾏过程中会创建一个个的可执⾏上下⽂ 每个可执⾏上下⽂的词法环境中包含了对外部词法环境的引⽤
简而言之: 函数内部 可以访问到 函数外部作用域的变量, 而外部函数还可以访问到全局作用域的变量,
函数内访问变量时,优先使用自己内部声明的变量;如果没有,就访问外部函数作用域的变量,如果也没有,则继续往外找。。直到找到全局。
垃圾回收
垃圾回收:使用完毕,由垃圾回收自动回收不再使用的内存===( 释放不在使用的内存
)
全局变量一般不会回收, 一般局部变量的的值, 不用了, 会被自动回收掉
两种常见的浏览器垃圾回收算法: 引用计数( IE ) 和 标记清除法
标记清除法
: 从js根部,如法访问到,无法触及(谁都找不到这块空间),这块空间就是垃圾,需要被回收。
原型链
每一个实例对象上有一个proto属性,指向的构造函数的原型对象,构造函数的原型
对象也是一个对象,也有proto属性,通过这个属性可以访问对象的原型,这样一层一层往上找的过程就形成了原型链。
判断是否是数组
方法一: 使用 toString
方法 :Object.prototype.toString.call(arr)
方法二: 使用 ES6 新增的 Array.isArray
方法 : Array.isArray(arr)
this的指向
1,普通函数
,定时器
和自调用函数
中的this指向window.
2.、事件中的this指向事件的调用者 ==谁调用我,我就指向谁.
3.、 构造函数中this和原型对象中的this,都是指向构造函数new 出来实例对象
4 . 箭头函数没有this
Promise
Promise 是异步编程的一种解决方案,它可以解决回调地狱的问题。Promise 是一个对象,可以从该对象获取异步操作的消息。
promise的三个状态: pending(默认) fulfilled(成功) rejected(失败)
如何识别数组和对象
1.通过constructor ==访问构造函数,我们可通过这个属性判断变量的数据类型
2.通过Object.prototype.toString.call()
3.通过instanceof
4.ES5特地新增isArray()检测变量是否是数组
new都做了那些事
1.创建一个空对象
2.this指向这个对象 (指向了构造函数的prototype
属性)
3.给这个对象赋值
4.返回这个对象
防抖和节流
1.防抖
:指在一段时间内,无论触发了多少次回调,都只执行最后一次。
原理:利用定时器,函数在第一次执行时设定一个定时器,并且通过闭包缓存起来,之后调用时发现已经设定过定时器就清空之前的定时器,并重新设定一个新的定时器,如果存在没有被清空的定时器,当定时器计时结束后触发函数执行。
/*
* 防抖函数
* @param fn 事件触发的操作
* @param delay 多少毫秒内连续触发事件,不会执行
* @returns {Function}
*/
function debounce(fn,delay) {
let timer = null; //通过闭包缓存了一个定时器
return function () {
const args = [...arguments];
const that = this
timer && clearTimeout(timer);
timer = setTimeout(function () {
fn.apply(that,args);
},delay);
}
}
window.onscroll = debounce(function () {
let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
console.log('滚动条位置:' + scrollTop);
},200)
2.节流
:在一定时间间隔内,只执行第一次。函数节流非常适用于函数被频繁调用的场景,例如:window.onresize() 事件、mousemove 事件、上传进度等情况
原理: 实现原理就是通过一个布尔类型变量来判断是否可执行回调,当变量为true时,生成一个定时器,同时将变量取反通过闭包保存起来,当定时器执行完回调后,再将变量变为true,在变量为false期间,调用节流函数不会生成定时器。
/**
* 节流函数
* @param fn 事件触发的操作
* @param delay 间隔多少毫秒需要触发一次事件
* @returns {Function}
*/
function throttle(fn, delay) {
let flag = true;
return function () {
if (!flag) {
return;
}
const that = this
const args = [...arguments];
flag = false;
setTimeout(() => {
fn.apply(that, args);
flag = true;
}, delay);
}
}
window.onscroll = debounce(function () {
let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
console.log('滚动条位置:' + scrollTop);
},200)
使用场景:1.滚动事件 2.输入的模糊搜索 3.轮播图切换 4.点击操作
事件循环机制 Eventloop
JavaScript是一个单线程的脚本语言。异步任务交给浏览器处理,
微任务(Microtasks)、宏任务(task)皆是异步任务,执行顺序如下:
同步任务
===>执行单个宏任务
===>先执行宏任务里的微任务
===>宏任务
宏任务: 1.主线程上的执行栈中所有的代码块
2.setTimeout
3.setInterval
4.Ajax
5.事件
微任务: 1.Promise.then
2.process.nextTick(Node.js 环境)
arguments
1.什么是arguments?
在函数调用的时候,浏览器每次都会传递进两个隐式参数:
一个是函数的上下文对象this
,另一个则是封装实参的类数组对象arguments
。arguments 是一个类数组对象,是函数实参的集合,是一个伪数组。
2.arguments方法:
一:转数组 Array.from() , [...arguments]
function fun2() {
let len = arguments.length;
let newArr = Array.from(arguments);
newArr.push(1);
console.log(newArr)
}
fun2("a", 0, { name: "cao" });
输出:['a',0,{ foo: "Hello, arguments" },1]
function fun2() {
let newArr = [...arguments];
newArr.push(1)
console.log(newArr)
}
fun2("a", 0, { name: "cao" });
输出:['a',0,{ foo: "Hello, arguments" },1]
二:调用原型方法: Array.prototype.slice.call(arguments) ,[].slice.call(arguments)
function fun2() {
let len = arguments.length;
let newArr = Array.prototype.slice.call(arguments);//用的数组原型
newArr.push(1)
console.log(newArr)
}
fun2("a", 0, { name: "cao" });
输出:['a',0,{ foo: "Hello, arguments" },1]
function fun2() {
let len = arguments.length;
let newArr = [].slice.call(arguments);//用的数组
newArr.push(1);
console.log(newArr)
}
fun2("a", 0, { name: "cao" });
输出:['a',0,{ foo: "Hello, arguments" },1]
3.箭头函数没有arguments。 使用剩余参数表示法...rest
Html
水平垂直居中
一: 绝对定位和负magin值
二: 绝对定位 + transform
三: flex布局
内联元素居中布局:
- 水平居中
- 行内元素可设置:text-align: center;
- flex布局设置父元素:display: flex; justify-content: center;
- 垂直居中
- 单行文本父元素确认高度:height === line-height
- 多行文本父元素确认高度:disaply: table-cell; vertical-align: middle;
块级元素居中布局
- 水平居中
- 定宽: margin: 0 auto;
- 不定宽: 参考上诉例子中不定宽高例子。
- 垂直居中
- position: absolute设置left、top、margin-left、margin-to(定高);
- position: fixed设置margin: auto(定高);
- display: table-cell;
- transform: translate(x, y);
- flex(不定高,不定宽);
- grid(不定高,不定宽),兼容性相对比较差;
绝对定位和相对定位的区别
相对定位: 是相对于它本身所在的文档流的位置进行定位,不会脱离文档流,定位前的位置依然保留。
绝对定位: 相对于它最近的设置过position某些属性(如:relative、obsolute、fixed、sticky )的父级结点来进行定位。如果祖先节点中没有设置,默认相对于浏览器窗口定位。会脱离文档流,文档中不会保留其定位前的位置
- relation 相对定位,相对于自己的文档流的位置定位,不会脱离文档流
- absolute 绝对定位,相对于具有relative、obsolute、fixed、sticky 的最近的父容器来定位,会脱离文档流
- fixed 绝对定位(通常叫做:固定定位),相对于window位置定位,会脱离文档流
http
http的缓存
HTTP 缓存分为 2 种,一种是强缓存,另一种是协商缓存。主要作用是可以加快资源获取速度,提升用户体验,减少网络传输,缓解服务端的压力。
强缓存 (验证缓存是否过期) :(进行判断缓存是否有效, 就是判断资源是否过期, 如果未过期, 直接用缓存)
协商缓存:若未命中强缓存(强缓存过期了),则浏览器会将请求发送至服务器。
服务器根据http头信息中的Last-Modify/If-Modify-Since
或Etag/If-None-Match
来判断是否命中协商缓存。
如果命中,则http返回码为304 (你本地之前加载的资源是有效的),浏览器从缓存中加载资源。
css
css怎么做动画
css 实现动画的三种方式总结:
- transition 过渡
- transform 变形 。
- animation 关键帧动画
1.transition 过渡动画:
1. 语法:
1. transition: 属性是个复合属性 。
2. transition: property duration timing-function delay
3. 默认值为: transition: all 0 ease 0;
2. 属性介绍:
1. transition-property: 规定设置过渡效果的 css 属性名称 。
2. transition-duration: 规定完成过渡效果需要多少秒或毫秒 。
3. transition-timing-function: 指定过渡函数, 规定速度效果的速度曲线 。
4. transition-delay: 指定开始出现的延迟时间 。
3. 子属性详解:
1. transition-property: none |all |property;
1. 值为 none 时, 没有属性会获得过渡效果
2. 值为 all 时, 所有属性都将获得过渡效果
3. 值为指定的 css 属性应用过渡效果, 多个属性用逗号隔开
4. css 属性实际使用时的设置:
1. color: background-color, border-color, color, outline-color ;
2. length: 真实的数字 如:word-spacing,width,vertical-align,top,right,bottom,left,padding,outline-width,margin,min-width,min-height,max-width,max-height,line-height,height,border-width,border-spacing,
3. integer: 离散步骤(整个数字), 在真实的数字空间, 以及使用 floor() 转换为整数时发生 如: outline-offset,z-index 。
4. number: 真实的(浮点型)数值, 如:zoom, opacity, font-weight 。
5. rectangle: 通过 x, y, width 和 height(转为数值)变换,如: crop 。
6. visibility: 离散步骤, 在0到1数字范围之内, 0表示“隐藏”, 1表示完全"显示"; 如: visibility 。
7. shadow: 作用于 color, x, y 和 blur(模糊)属性; 如:text-shadow 。
8. background-image: 通过每次停止时的位置和颜色进行变化 。 它们必须有相同的类型(放射状的或是线性的)和相同的停止数值以便执行动画 。
2. transition-duration
1. transition-duration: time;
2. 该属性主要用来设置一个属性过渡到另一个属性所需的时间, 也就是从旧属性过渡到新属性花费的时间长度, 俗称持续时间
3. transition-timing-function: linear| ease| ease-in| ease-out| ease-in-out| cubic-bezier(n,n,n,n);
1. 该属性指的是过渡的 “缓动函数” 。 主要用来指定浏览器的过渡速度, 以及过渡期间的操作进展情况 。
2. 注意: 值 cubic-bezier(n,n,n,n) 可以定义自己的值, 如 cubic-bezier(0.42,0,0.58,1) 。
3. 各个子属性详细解析:
1. linear: 匀速 (约等于)== cubic-bezier(0,0,1,1) 。
2. ease: 慢快慢 (约等于)== cubic-bezier(0.25,0.1,0.25,0.1) 。
3. ease-in: 慢速开始的过渡 (约等于)== cubic-bezier(0.45,0.,1,1) 。
4. ease-out: 慢速结束的过渡 (约等于)== cubic-bezier(0,0.,0.58,1) 。
5. ease-in-out: 慢速开始和结束的过渡 (约等于)== cubic-bezier(0.45,0.,0.58,1) 。
6. cubic-bezier(n,n,n,n): 在 cubic-bezier 函数中定义自己的值; 可能的值是0~1之间的数值 。
4. transition-delay
1. 这个属性没什么说的了, 就是过渡效果开始前的延迟时间, 单位秒或者毫秒
2.transform 变形
1. 可以利用 transform 功能来实现文字或图像的 旋转、缩放、倾斜、移动 这四种类型的变形处理
1. 旋转 rotate
1. 用法: transform: rotate(45deg);
2. 提供一个参数 “角度”, 单位 deg 为度的意思, 正数为顺时针旋转, 负数为逆时针旋转, 上述代码作用是顺时针旋转45度
2. 缩放 scale
1. 用法: transform: scale(0.5) 或者 transform: scale(0.5, 2);
2. 一个参数时: 表示水平和垂直同时缩放该倍率
3. 两个参数时: 第一个参数指定水平方向的缩放倍率, 第二个参数指定垂直方向的缩放倍率 。
3. 倾斜 skew
1. 用法: transform: skew(30deg) 或者 transform: skew(30deg, 30deg);
2. 一个参数时: 表示水平方向的倾斜角度 。
3. 两个参数时: 第一个参数表示水平方向的倾斜角度, 第二个参数表示垂直方向的倾斜角度 。
4. skew 的默认原点 transform-origin 是这个物件的中心点
4. 移动 translate
1. 用法: transform: translate(45px) 或者 transform: translate(45px, 150px);
2. 一个参数时: 表示水平方向的移动距离;
3. 两个参数时: 第一个参数表示水平方向的移动距离, 第二个参数表示垂直方向的移动距离 。
2. 基准点 transform-origin
1. 在使用 transform 方法进行文字或图像的变形时, 是以元素的中心点为基准点进行的 。 使用 transform-origin 属性, 可以改变变形的基准点
2. 用法: transform-origin: 10px 10px;
3. 表示相对左上角原点的距离, 单位 px, 第一个参数表示相对左上角原点水平方向的距离, 第二个参数表示相对左上角原点垂直方向的距离;
4. 两个参数除了可以设置为具体的像素值, 其中第一个参数可以指定为 left、center、right, 第二个参数可以指定为 top、center、bottom。
3. 多方法组合变形
1. 用法: transform: rotate(45deg) scale(0.5) skew(30deg, 30deg) translate(100px, 100px);
2. 这四种变形方法顺序可以随意, 但不同的顺序导致变形结果不同, 原因是变形的顺序是从左到右依次进行
3.animation 关键帧动画
1. 在 CSS3 中创建动画, 您需要学习 @keyframes 规则 。
2. @keyframes 规则用于创建动画 。 在 @keyframes 中规定某项 CSS 样式, 就能创建由当前样式逐渐改为新样式的动画效果 。
3. 必须定义动画的名称和时长 。 如果忽略时长, 则动画不会允许, 因为默认值是 0。
4. 请用百分比来规定变化发生的时间, 或用关键词 "from" 和 "to", 等同于 0% 和 100% 。
5. 语法: animation: name duration timing-function delay iteration-count direction;
1. animation-name 规定需要绑定到选择器的 keyframe 名称*
2. animation-duration 规定动画完成一个周期所花费的秒或毫秒。默认是 0。
3. animation-timing-function 规定动画的速度曲线。 默认是 "ease"。
1. linear 动画从头到尾的速度是相同的。
2. ease 默认。动画以低速开始,然后加快,在结束前变慢。
3. ease-in 动画以低速开始。
4. ease-out 动画以低速结束。
5. ease-in-out 动画以低速开始和结束。
6. cubic-bezier(n,n,n,n) 在 cubic-bezier 函数中自己的值。可能的值是从 0 到 1 的数值。
4. animation-delay 规定动画何时开始 。 默认是 0。
5. animation-iteration-count 规定动画被播放的次数 (from到to算作一次, to到from算作一次; 注意计算方式) 。
1. 默认是 1 。
2. infinite规定动画应该无限次播放。
6. animation-direction 规定动画是否在下一周期逆向地播放 。 默认是 "normal"; alternate (轮流),。
1. normal 默认值。动画按正常播放。
2. reverse 动画反向播放。
3. alternate 动画在奇数次(1、3、5...)正向播放,在偶数次(2、4、6...)反向播放。
4. alternate-reverse 动画在奇数次(1、3、5...)反向播放,在偶数次(2、4、6...)正向播放。
5. initial 设置该属性为它的默认值 。
6. 子属性详解
1. alternate(轮流):
1. alternate (轮流): 动画播放在第偶数次向前播放, 第奇数次向反方向播放 (animation-iteration-count 取值大于1时设置有效
2. 语法: animation-direction: alternate;
2. animation-play-state 规定动画是否正在运行或暂停 。 默认是 "running" 播放; paused 暂停播放 。
1. 语法: animation-play-state: paused;
3. animation-fill-mode 属性规定动画在播放之前或之后, 其动画效果是否可见; 规定对象动画时间之外的状态; none | forwards | backwards | both 。
1. none: 不改变默认行为 (默认, 回到动画没开始时的状态) 。
2. forwards: 当动画完成后,保持最后一个属性值(在最后一个关键帧中定义) (动画结束后动画停留在结束状态) 。
3. backwards: 在 animation-delay 所指定的一段时间内, 在动画显示之前, 应用开始属性值 (在第一个关键帧中定义) (动画回到第一帧的状态)。
4. both: 向前和向后填充模式都被应用 (根据 animation-direction 轮流应用 forwards 和 backwords 规则)。
5. 语法: animation-fill-mode: forwards
1. 0% 是动画的开始, 100% 是动画的完成。
移动端rem适配
Vant 中的样式默认使用 px
作为单位,如果需要使用 rem
单位,推荐使用以下两个工具:
- postcss-pxtorem 是一款 postcss 插件,用于将单位转化为 rem
- lib-flexible 用于设置 rem 基准值
一、使用 lib-flexible 动态设置 REM 基准值(html 标签的字体大小)
1、安装
# yarn add amfe-flexible
npm i amfe-flexible
2、然后在 main.js
中加载执行该模块
import 'amfe-flexible'
最后测试:在浏览器中切换不同的手机设备尺寸,观察 html 标签 font-size
的变化。
二、使用 postcss-pxtorem 将 px
转为 rem
1、安装
# yarn add -D postcss-pxtorem
# -D 是 --save-dev 的简写
npm install postcss-pxtorem -D
2、然后在项目根目录中创建 .postcssrc.js
文件
module.exports = {
plugins: {
'autoprefixer': {
browsers: ['Android >= 4.0', 'iOS >= 8']
},
'postcss-pxtorem': {
rootValue: 37.5,
propList: ['*']
}
}
}
3、配置完毕,重新启动服务
最后测试:刷新浏览器页面,审查元素的样式查看是否已将 px
转换为 rem
。
(1)PostCSS 介绍
PostCSS 是一个处理 CSS 的处理工具,本身功能比较单一,它主要负责解析 CSS 代码,再交由插件来进行处理,它的插件体系非常强大,所能进行的操作是多种多样的,例如:
- Autoprefixer 插件可以实现自动添加浏览器相关的声明前缀
- PostCSS Preset Env 插件可以让你使用更新的 CSS 语法特性并实现向下兼容
- postcss-pxtorem 可以实现将 px 转换为 rem
- ...
目前 PostCSS 已经有 200 多个功能各异的插件。开发人员也可以根据项目的需要,开发出自己的 PostCSS 插件。