webpack相关 https://blog.csdn.net/sinat_17775997/article/details/84314006
react相关 https://www.imooc.com/article/309371
JavaScript中常见的八个陷阱总结 https://www.jb51.net/article/117337.htm
0.react和vue
1、监听数据变化的实现原理不同
Vue通过 getter/setter以及一些函数的劫持,能精确知道数据变化。
React默认是通过比较引用的方式(diff)进行的,如果不优化可能导致大量不必要的VDOM的重新渲染。为什么React不精确监听数据变化呢?这是因为Vue和React设计理念上的区别,Vue使用的是可变数据,而React更强调数据的不可变,两者没有好坏之分,Vue更加简单,而React构建大型应用的时候更加棒。
2、数据流的不同
Vue1.0中可以实现两种双向绑定:父子组件之间,props可以双向绑定;组件与DOM之间可以通过v-model双向绑定。Vue2.x中去掉了第一种,也就是父子组件之间不能双向绑定了(但是提供了一个语法糖自动帮你通过事件的方式修改),并且Vue2.x已经不鼓励组件对自己的 props进行任何修改了。
React不支持双向绑定需要自己实现,提倡的是单向数据流,称之为onChange/setState()模式。不过由于我们一般都会用Vuex以及Redux等单向数据流的状态管理框架,因此很多时候我们感受不到这一点的区别了。
3、HoC和mixins
HoC和mixinsVue组合不同功能的方式是通过mixin,Vue中组件是一个被包装的函数,并不简单的就是我们定义组件的时候传入的对象或者函数。比如我们定义的模板怎么被编译的?比如声明的props怎么接收到的?这些都是vue创建组件实例的时候隐式干的事。由于vue默默帮我们做了这么多事,所以我们自己如果直接把组件的声明包装一下,返回一个HoC,那么这个被包装的组件就无法正常工作了。
React组合不同功能的方式是通过HoC(高阶组件)。React最早也是使用mixins的,不过后来他们觉得这种方式对组件侵入太强会导致很多问题,就弃用了mixinx转而使用HoC。高阶组件本质就是高阶函数,React的组件是一个纯粹的函数,所以高阶函数对React来说非常简单。
4、组件通信的区别
Vue中有三种方式可以实现组件通信:父组件通过props向子组件传递数据或者回调,虽然可以传递回调,但是我们一般只传数据;子组件通过事件向父组件发送消息;通过V2.2.0中新增的provide/inject来实现父组件向子组件注入数据,可以跨越多个层级。React中也有对应的三种方式:父组件通过props可以向子组件传递数据或者回调;可以通过 context 进行跨层级的通信,这其实和 provide/inject 起到的作用差不多。React 本身并不支持自定义事件,而Vue中子组件向父组件传递消息有两种方式:事件和回调函数,但Vue更倾向于使用事件。在React中我们都是使用回调函数的,这可能是他们二者最大的区别。
5.模板渲染方式的不同
在表层上,模板的语法不同,React是通过JSX渲染模板。而Vue是通过一种拓展的HTML语法进行渲染,但其实这只是表面现象,毕竟React并不必须依赖JSX。
在深层上,模板的原理不同,这才是他们的本质区别:React是在组件JS代码中,通过原生JS实现模板中的常见语法,比如插值,条件,循环等,都是通过JS语法实现的,更加纯粹更加原生。而Vue是在和组件JS代码分离的单独的模板中,通过指令来实现的,比如条件语句就需要 v-if 来实现对这一点,这样的做法显得有些独特,会把HTML弄得很乱。
举个例子,说明React的好处:react中render函数是支持闭包特性的,所以我们import的组件在render中可以直接调用。但是在Vue中,由于模板中使用的数据都必须挂在 this 上进行一次中转,所以我们import 一个组件完了之后,还需要在 components 中再声明下,这样显然是很奇怪但又不得不这样的做法。
6、渲染过程不同
Vue可以更快地计算出Virtual DOM的差异,这是由于它在渲染过程中,会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树。
React在应用的状态被改变时,全部子组件都会重新渲染。通过shouldComponentUpdate这个生命周期方法可以进行控制,但Vue将此视为默认的优化。
如果应用中交互复杂,需要处理大量的UI变化,那么使用Virtual DOM是一个好主意。如果更新元素并不频繁,那么Virtual DOM并不一定适用,性能很可能还不如直接操控DOM。
7.Vuex和Redux的区别
从表面上来说,store注入和使用方式有一些区别。在Vuex中,$store被直接注入到了组件实例中,因此可以比较灵活的使用:使用dispatch、commit提交更新,通过mapState或者直接通过this.$store来读取数据。在Redux中,我们每一个组件都需要显示的用connect把需要的props和dispatch连接起来。另外,Vuex更加灵活一些,组件中既可以dispatch action,也可以commit updates,而Redux中只能进行dispatch,不能直接调用reducer进行修改。
从实现原理上来说,最大的区别是两点:Redux使用的是不可变数据,而Vuex的数据是可变的,因此,Redux每次都是用新state替换旧state,而Vuex是直接修改。Redux在检测数据变化的时候,是通过diff的方式比较差异的,而Vuex其实和Vue的原理一样,是通过getter/setter来比较的,这两点的区别,也是因为React和Vue的设计理念不同。React更偏向于构建稳定大型的应用,非常的科班化。相比之下,Vue更偏向于简单迅速的解决问题,更灵活,不那么严格遵循条条框框。因此也会给人一种大型项目用React,小型项目用Vue的感觉。
解释一下典型的react 和 redux数据流。
首先是dispatch一个action。然后reducer会收到这个action, 根据这个action对状态进行修改store。状态修改以后会被处理容器捕捉到。从而对相关的界面进行更新
———————————————
1.介绍一下Javascript的执行上下文?
执行上下文有且只有三类,全局执行上下文,函数上下文,与eval上下文;eval一般不会使用。
全局执行上下文只有一个,在客户端中一般由浏览器创建,也就是我们熟知的window对象,我们能通过this直接访问到它。
函数执行上下文可存在无数个,每当一个函数被调用时都会创建一个函数上下文;需要注意的是,同一个函数被多次调用,都会创建一个新的上下文。
执行上下文栈也叫调用栈,执行栈用于存储代码执行期间创建的所有上下文,具有LIFO(Last In First Out后进先出,也就是先进后出)的特性。
JS代码首次运行,都会先创建一个全局执行上下文并压入到执行栈中,之后每当有函数被调用,都会创建一个新的函数执行上下文并压入栈内;由于执行栈LIFO的特性,所以可以理解为,JS代码执行完毕前在执行栈底部永远有个全局执行上下文。
2.NaN 是什么,用 typeof 会输出什么?
NaN 是 ‘not a number’ 的缩写,表示 “不是一个数字”
通常会在一个数字和其他类型运算过程中产生:
虽然它 “不是一个数字”,但是 NaN 的 typeof 结果却是 number
console.log(typeof (NAN)); // number
NaN 和任何变量都不相等,包括 NaN 自己
console.log(NaN === NaN); // false
判断一个变量是不是 NaN 可以用 isNaN()方法或者Number.isNaN()方法
3.instance 如何使用?
在书面语中,实例是实际的例子,而在计算机语音中,实例就是一个类的真实对象,类在实例化后就叫做一个实例。类是静态的,不占进程内存,而实例拥有动态内存。通俗的说,打个比方,汽车是一个类,张三的车,李四的车就是汽车的实例。
实例和对象的区别
实例是类的具象化产品
对象是一个具有多种属性的内容结构
实例都是对象,而对象不全是实例
instance 如何使用
instance通过new操作符来创建实例对象,它可以用来判断对象是否是某个类或构造函数的实例。
创建一个实例有三种方式:
关键字 new 创建:var ins = new Object(); ins.name = "dandan"; ins.job = "javascript";
工厂模式创建:function createInstance(name,job){var ins = new Object();ins.name = name;ins.job = job;ins.sayName = function(){alert(this.name);}return ins;}
构造函数模式:function createInstance(name,job){this.name = name;this.job = job;this.sayName = function(){alert(this.name);}}
4.函数中的arguments是数组吗?类数组转数组的方法了解一下?
不是
类数组转数组
Array.from()
[...arguments]
5.
闭包的定义
闭包指的是那些引用了另一个函数作用域中变量的函数,通常是在嵌套函数中实现的
闭包的优缺点
优点:对私有变量进行保护和保存,创建一个安全的环境,保证内部代码不受到外部的干涉,(实现私有成员,对外只暴露几个接口)
缺点:如果使用不当会造成内存泄漏
闭包的应用
函数的防抖和节流,唯一弹窗,浏览器判断以及柯里化函数、compose组合函数,react树状更新机制等都应用到了闭包。
//防抖
function debounce(func,wait,...args){
let timeout; //延时器变量
return function(){
const context = this;
if (timeout) clearTimeout(timeout);
let callNow = !timeout; //是否立即执行
timeout = setTimeout(() => {
timeout = null;
},wait)
if(callNow) func.apply(context,args)
}
}
单例模式前端最典型的应用场景,全局唯一消息框
```html
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.model {
width: 200px;
height: 200px;
border: 1px solid aqua;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
}
</style>
</head>
<body>
<div id="loginBtn">点我</div>
<script>
var getSingle = function (fn) {
var result; //缓存实例
return function () {
return result || (result = fn.apply(this, arguments))
}
}
var createLoginLayer = function () {
var oDiv = document.createElement("div");
oDiv.innerHTML = "我是登录浮窗";
oDiv.className = "model";
oDiv.style.display = "none";
document.body.appendChild(oDiv);
return oDiv;
}
var createSingleLoginLayer = getSingle(createLoginLayer);
document.getElementById("loginBtn").onclick = function () {
//动态创建弹窗
//新建一个弹窗实例,内部使用单例模式管理,一直只能有一个.
var loginLayer = createSingleLoginLayer();
loginLayer.style.display = "block"
}
</script>
</body>
```
(1)柯里化函数【偏应用函数】
是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。
1.函数复用
// 正常正则验证字符串
reg.test(txt)
// 函数封装后
function check(reg,txt){
returnreg.test(txt)
}
check(/\d+/g,'test')//false
check(/[a-z]+/g,'test')//true
// Currying后
function curryingCheck(reg){
return function(txt){
return reg.test(txt)
}}
var hasNumber=curryingCheck(/\d+/g)
var hasLetter=curryingCheck(/[a-z]+/g)
hasNumber('test1')// true
hasNumber('testtest')// false
hasLetter('21212')// false
2. 提前确认
var on = function(element, event, handler) { if (document.addEventListener) { if (element && event && handler) { element.addEventListener(event, handler, false); } } else { if (element && event && handler) { element.attachEvent('on' + event, handler); } }}var on = (function() { if (document.addEventListener) { return function(element, event, handler) { if (element && event && handler) { element.addEventListener(event, handler, false); } }; } else { return function(element, event, handler) { if (element && event && handler) { element.attachEvent('on' + event, handler); } }; }})();
//换一种写法可能比较好理解一点,上面就是把isSupport这个参数给先确定下来了var on = function(isSupport, element, event, handler) { isSupport = isSupport || document.addEventListener; if (isSupport) { return element.addEventListener(event, handler, false); } else { return element.attachEvent('on' + event, handler); }}
curry的一些性能问题你只要知道下面四点就差不多了:
存取arguments对象通常要比存取命名参数要慢一点
一些老版本的浏览器在arguments.length的实现上是相当慢的
使用fn.apply( … ) 和 fn.call( … )通常比直接调用fn( … ) 稍微慢点
创建大量嵌套作用域和闭包函数会带来花销,无论是在内存还是速度上
其实在大部分应用中,主要的性能瓶颈是在操作DOM节点上,这js的性能损耗基本是可以忽略不计的,所以curry是可以直接放心的使用。
类库封装,rollup, 构建器打包 webpack
webpack更适合打包组件库、应用程序之类的应用,而rollup更适合打包纯js的类库。
6. new 一个构造函数,如果函数返回 return {} 、 return null , return 1 , return true 会发生什么情况?
只有在构造函数 return 的数据类型是 Object 时才会执行该 return 语句,其余情况均返回该构造函数的一个实例。
return {} 返回空对象,
其余情况返回实例。
7.symbol 有什么用处?
Symbol是原始类型,
可以给对象设置唯一值类型的属性
把Symbol作为对象,它提供了很多静态方法,是JS很多底层的实现原理出处
- Symbol.toPrimitive
- Symbol.hasInstance
- Symbol.toStringTag
- Symbol.iterator
- Symbol.asyncIterator
vuex/redux中需要派发很多行为标识,可以把这些行为标识统一管理,利用Symbol的唯一性来进行管理实现
8.判断数据类型的方式有哪些?
string,number,object,boolean,undefined,null,symbol,bigint
1.null === undefined 但是null == undefined
== 代表相同, ===代表严格相同, 为啥这么说呢,
这么理解: 当进行双等号比较时候: 先检查两个操作数数据类型,如果相同, 则进行===比较, 如果不同, 则愿意为你进行一次类型转换, 转换成相同类型后再进行比较, 而===比较时, 如果类型不同,直接就是false.
2.undefined不是保留值,直接定义会有危险可以用void 0
3.null代表空值,undefined代表未定义
9.如何判断一个对象是不是空对象?
使用 Object.keys(obj).length 为 0,说明是空对象
10.call 、bind 、 apply 区别
call 、bind 、 apply 这三个函数的第一个参数都是 this 的指向对象:
call 的参数是直接放进去的,第二第三第 n 个参数全都用逗号分隔,直接放到后面 obj.myFun.call(db,'成都', ... ,'string' )。
apply 的所有参数都必须放在一个数组里面传进去 obj.myFun.apply(db,['成都', ..., 'string' ])。
bind 除了返回是函数以外,它 的参数和 call 一样。
当然,三者的参数不限定是 string 类型,允许是各种类型,包括函数 、 object 等等!
11.判断数组类型的方法
var arr = []
arr.constructor === Array // true
Array.isArray(arr)
Object.prototype.toString.call(arr) === '[object Array]'
arr instanceof Array
Array.prototype.isPrototypeOf(arr)
12.分析一下箭头语法为什么不能当做构造函数
是因为箭头函数没有 [[Construct]] 。如果通过new调用,就会出错
functionPerson(){}
console.log(Person.prototype);
// {constructor: ƒ}
let Animal=()=>{};
console.log(Animal.prototype);
// undefined
注意点:
箭头函数没有自己的 this,而是继承父作用域的 this
不支持 call bind,改变 this 指向。
不绑定 arguments
没有 prototype 属性
13.你知道webpack的作用是什么吗?
模块打包。可以将不同模块的文件打包整合在一起,并且保证它们之间的引用正确,执行有序。利用打包我们就可以在开发的时候根据我们自己的业务自由划分文件模块,保证项目结构的清晰和可读性。
编译兼容。在前端的“上古时期”,手写一堆浏览器兼容代码一直是令前端工程师头皮发麻的事情,而在今天这个问题被大大的弱化了,通过webpack的Loader机制,不仅仅可以帮助我们对代码做polyfill,还可以编译转换诸如.less, .vue, .jsx这类在浏览器无法识别的格式文件,让我们在开发的时候可以使用新特性和新语法做开发,提高开发效率。
能力扩展。通过webpack的Plugin机制,我们在实现模块化打包和编译兼容的基础上,可以进一步实现诸如按需加载,代码压缩等一系列功能,帮助我们进一步提高自动化程度,工程效率以及打包输出的质量。
14.说一下模块打包运行的原理
如果面试官问你Webpack是如何把这些模块合并到一起,并且保证其正常工作的,你是否了解呢?
首先我们应该简单了解一下webpack的整个打包流程:
1、读取webpack的配置参数;
2、启动webpack,创建Compiler对象并开始解析项目;
3、从入口文件(entry)开始解析,并且找到其导入的依赖模块,递归遍历分析,形成依赖关系树;
4、对不同文件类型的依赖模块文件使用对应的Loader进行编译,最终转为Javascript文件;
5、整个过程中webpack会通过发布订阅模式,通过plugin注入钩子,而webpack的插件即可通过监听这些关键的事件节点,执行插件任务进而达到干预输出结果的目的。
其中文件的解析与构建是一个比较复杂的过程,在webpack源码中主要依赖于compiler和compilation两个核心对象实现。
compiler对象是一个全局单例,他负责把控整个webpack打包的构建流程。compilation对象是每一次构建的上下文对象,它包含了当次构建所需要的所有信息,每次热更新和重新构建,compiler都会重新生成一个新的compilation对象,负责此次更新的构建过程。
而每个模块间的依赖关系,则依赖于AST语法树。每个模块文件在通过Loader解析完成之后,会通过acorn库生成模块代码的AST语法树,通过语法树就可以分析这个模块是否还有依赖的模块,进而继续循环执行下一个模块的编译解析。
最终Webpack打包出来的bundle文件是一个IIFE的执行函数。
优化
0.优化Loader 对于Loader来说,首先优化的当是babel了,babel会将代码转成字符串并生成AST,然后继续转化成新的代码,转换的代码越多,效率就越低。优化Loader的搜索范围,include: [resolve('src')],// 只在src文件夹下查找。可以将babel编译过文件缓存起来,以此加快打包时间,主要在于设置cacheDirectory,loader:'babel-loader?cacheDirectory=true'
1.webpack打包出来的文件,减少缓存可以用hash:true
2.启用用gzip,压缩html和css代码,通过配置删除console.log和debugger等,防止可能造成的内存泄漏
3.Tree shaking生产环境它会删除项目中未被引用的代码
4.DllPlugin该插件可以将特定的类库提前打包然后引入
15.innerHTML、 nodeValue与 textContent之间的区别
element.innerHTML设置或获取HTML语法表示的元素的后代, 顾名思义就是返回DOM节点的子HTML代码, 如果是设置的话会解析HTML(会遭到恶意攻击)
node.nodeValue 一般用来获取文本节点的值
node.textContent获取节点及子节点的文本内容,而且不会受css影响会返回隐藏的节点的内容,设置内容不会解析成HTML
<div id="test">
123
<span>456</span>
<span style="display:none;">789</span>
</div>
<script>
const testDOM = document.getElementById('test')
const innerHTMLStr = testDOM.innerHTML
const nodeValueStr = testDOM.childNodes[0].nodeValue
const textContent = testDOM.textContent
console.log(innerHTMLStr)
// '\n 123\n<span>456</span><span style="display:none;">789</span>\n'
console.log(nodeValueStr)
// '\n 123\n '
console.log(textContent)
// '\n 123\n 456789\n'
</script>
16.怎样添加、移除、移动、复制、创建和查找节点?
(1)创建新节点
createDocumentFragment() //创建一个DOM片段
createElement() //创建一个具体的元素
createTextNode() //创建一个文本节点
(2)添加、移除、替换、插入、复制
appendChild() //添加
removeChild() //移除
replaceChild() //替换
insertBefore() //在已有的子节点前插入一个新的子节点
cloneNode() //复制
(3)查找
getElementsByTagName() //通过标签名称
getElementsByName()//通过元素的Name属性的值(IE容错能力较强,会得到一个数组,其中包括id等于 name值的)
getElementById() //通过元素Id,唯一性
17.输入框中只能输入数字 请输入您的年龄
JS代码如下所示:
//当按键按下时,阻止非数字字符的输入
function digitOnly(event) {
var code= event.keyCode | | event.which; //ie| |firefox if( (code<48) | | (code>57) ) {
if(event.preventDefault) { //firefox
event.preventDefault( ) ;
}
/ /当按键弹起时 , 剔除输入中的非中文字符——解决复制粘贴进来的非数字function filterChar(input){
input.value= input.value.replace(/ [^0-9] /g, ' ' ) ;
}
18.浏览器输入url后经历的过程
一般会经历以下几个过程:
1、首先,在浏览器地址栏中输入url
2、浏览器先查看浏览器缓存-系统缓存-路由器缓存,如果缓存中有,会直接在屏幕中显示页面内容。若没有,则跳到第三步操作。
3、在发送http请求前,需要域名解析(DNS解析),解析获取相应的IP地址。
4、浏览器向服务器发起tcp连接,与浏览器建立tcp三次握手。
5、握手成功后,浏览器向服务器发送http请求,请求数据包
6、服务器处理收到的请求,将数据返回至浏览器,四次挥手。https://m.sohu.com/a/221520733_465908
7、浏览器收到HTTP响应
8、读取页面内容,浏览器渲染,解析html源码
9、生成Dom树、解析css样式、js交互
10、客户端和服务器交互
11、ajax查询
其中,步骤2的具体过程是:
浏览器缓存:浏览器会记录DNS一段时间,因此,只是第一个地方解析DNS请求;
操作系统缓存:如果在浏览器缓存中不包含这个记录,则会使系统调用操作系统,获取操作系统的记录(保存最近的DNS查询缓存);
路由器缓存:如果上述两个步骤均不能成功获取DNS记录,继续搜索路由器缓存;
ISP缓存:若上述均失败,继续向ISP搜索。
19.如何最小化重绘(repaint)和回流(reflow)?
需要对元素进行复杂重绘时,可以先隐藏(display:"none"),操作完成后再显示.
需要创建多个DOM节点时,使用DocumentFragment创建完之后一次性的加入documnet
缓存Layout属性值,如:var left =elem.offsetLeft;这样,多次使用left产生一次回流
尽量避免用table布局(table元素一旦触发回流就会导致table里所有的其他元素回流)
避免使用css表达式(expression),因为每次调用都会重新计算值(包括加载页面)
尽量使用css属性简写,如:用border代替border-width,border-style,border-color
批量修改元素样式:element.style.xxx
重绘: 当页面中元素样式的改变并不影响它在文档流中的位置时,也就是说布局没有发生改变时(比如只是改变元素的颜色)。
回流:当渲染树(Render Tree)中的部分(或全部)元素的尺寸、结构、显示隐藏等发生改变时,浏览器重新渲染的过程称为回流。 简而言之,任何会改变元素几何信息(元素的位置和尺寸大小)的操作,都会触发回流。 回流是影响浏览器性能的关键 因素。
比如:
(1)添加或者删除可见的 DOM 元素(不可见元素不会触发回流);
(2)元素尺寸或位置发生改变
(3)元素内容变化,比如文字数量或图片大小
(4)浏览器窗口大小发生改变
(5)CSS伪类的激活(例如::hover,从而改变了元素的布局的)
注意
回流必定会发生重绘,重绘不一定会引发回流。
回流比重绘的代价要更高。有时即使仅仅回流一个单一的元素,它的父元素以及任何跟它相关的元素也会产生回流,牵一发动全身。
如何避免(减少)回流
css避免设置多层内联样式。
如果需要设置动画效果,最好将元素脱离正常的文档流。
避免使用CSS表达式(例如:calc())。避免频繁操作样式,最好将样式列表定义为class并一次性更改class属性。
避免频繁操作DOM,创建一个documentFragment,在它上面应用所有DOM操作,最后再把它添加到文档中。
可以先为元素设置为不可见:display: none,操作结束后再把它显示出来。
20.Sass、LESS
LESS的安装和Sass安装有所不同,他不需要依赖于Ruby环境,就能直接安装使用。不过LESS安装分为两种:客户端和服务器端安装
LESS样式中声明变量和调用变量和Sass一样,唯一的区别就是变量名前面使用的是“@”字符。LESS是CSS的一种扩展形式,它并没有阉割CSS的功能,而是在现有的CSS语法上,添加了很多额外的功能。
Sass声明变量必须是“$”开头,后面紧跟变量名和变量值,而且变量名和变量值需要使用冒号(:)分隔开。就像CSS属性设置一样,Sass也同时支持老的语法,老的语法和常规的CSS语法略有不同,他需要严格的语法,任何的缩进和字符的错误都会造成样式的编译错误。Sass可以省略大括号({})和分号(;),完全依靠严格的缩进和格式化代码
21.移动端你们一般采用什么布局?移动端设计稿是多大的尺寸?
定宽布局
一般移动端设计稿是640或者750的尺寸
22.em和rem的区别
em相对父级元素设置的font-size来设置大小 如果父元素没有设置font-size ,则继续向上查找,直至有设置font-size元素
rem直接参照html标签字体大小,并且所有使用rem单位的都是参照html标签,windowWidth/37.5
23.移动端click 300毫秒延迟原因?
移动端浏览器会有一些默认的行为,比如双击缩放、双击滚动。这些行为,尤其是双击缩放,主要是为桌面网站在移动端的浏览体验设计的。而在用户对页面进行操作的时候,移动端浏览器会优先判断用户是否要触发默认的行为。
24.固定定位布局 键盘挡住输入框内容?
// css
.mainBox{
height:100vh;
position:relative;
}
.inputBox{
position:absolute;
bottom:0;
}
// 输入框获得焦点事件
onFocus() {
setTimeout(function(){
// 设置body的高度为可视高度+302
// 302为原生键盘的高度
document.getElementsByTagName('body')[0].style.height= (window.innerHeight+ 302) + 'px';
document.body.scrollTop= 302;
}, 300)
}
// 输入框失去焦点事件
onBlur() {
// 设置body恢复原来的高度
document.getElementsByTagName('body')[0].style.height= window.innerHeight+ 'px';
}
低版本ios不支持fixed,为了兼容(IScroll.js可以支持fixed)
var u = navigator.userAgent, app = navigator.appVersion;
varisiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);//ios终端
if(isiOS) {
$('textarea').focus(function() {
window.setTimeout('scrollBottom()',500);
});
}
functionscrollBottom() {
window.scrollTo(0, $('body').height());
}
或者直接调用input时
document.body.scrollTop = document.body.scrollHeight;
https://www.cnblogs.com/guolao/p/11936709.html
25.移动端兼容问题?
scroll元素滑动,ios滑动比较生涩
解决办法:给父类设置-webkit-overflow-scrolling:touch
iphone及ipad下输入框默认内阴影
解决办法: 设置样式 -webkit-appearance:none;
IOS 在点击div的时候会出现黑灰色背景块
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
ios 长按出现拷贝、复制等菜单选项
-webkit-touch-callout: none;
/*系统默认菜单被禁用*/
-webkit-user-select: none;
/*webkit浏览器*/
-khtml-user-select: none;
/*早期浏览器*/
-moz-user-select: none;
/*火狐*/
-ms-user-select: none;
/*IE10*/
user-select: none;
背景图片设置,rentina屏幕下图片模糊
解决办法:使用2倍图或者background-size设为二分之一
ios系统中元素被触摸时产生的半透明灰色遮罩
解决办法:设置样式 -webkit-tap-highlight-color:rgba(255,255,255,0)
css width\height百分比值
百分比在低端机型上会有不同的表现,具体情况具体分析。(低版本的oppo和华为手机上面出现过)
解决办法:建议尽量不使用百分比,可以使用rem去实现。
使用css3控制背景图的切换
在手机上面效果卡顿,且切换会有问题
解决办法:使用css合并切换图层,使用css中的帧动画通过控制background-position来显示图片位置,这种写法手机上面兼容性较好
使用animation同时使用transform和rotate:
在手机上面效果被覆盖并且效果出问题
解决办法:transform3d增加一个z坐标数值
使用css中的scale影响图片变的模糊不清楚
原因:scale导致了页面的重排和重绘
解决办法:给css中加上translageZ(0)
ios机型使用圆角的overflow:hidden,会导致圆角遮罩不生效
解决办法:
overflow: hidden;
border-radius: 30px;
transform: rotate(0deg);
输入框在android版本小于10的手机中会有默认白色背景和边框,导致样式错乱.
background-color: transparent;
FILTER: alpha(opacity=0);//安卓兼容
h5 图片长按保存禁用
//慎用,因为设置次属性可能导致页面不能滚动,根据自己实际情况来采取即可
解决办法:img{
pointer-events:none;/* 禁止长按图片保存 */
}
禁止长按链接与图片弹出菜单
解决办法:a,img{ -webkit-touch-callout: none}
<meta name="App-Config" content="fullscreen=yes,useHistoryState=yes,transition=yes"/>
<meta content=yes name=apple-mobile-web-app-capable/>
<meta content=yes name=apple-touch-fullscreen/>
<meta content="telephone=no,email=no" name=format-detection/>
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no//禁用缩放,viewport-fit=cover"//iphonex适配>
iPhone上的Safari(还有些webkit android手机浏览器)会自动对看起来像是电话号码的数字串(包括已经加入连字符或括号格式化过的)添加电话链接,点击之后会询问用户是否想要拨打该号码。如果你不希望开启这个自动识别,可以将它关闭:
<meta name="format-detection" content="telephone=no" />
如果你关闭自动识别后,又希望某些电话号码能够链接到iPhone的拨号功能,那么可以通过这样来声明电话链接:
<a href="tel:13800138000">13800138000</a>
<meta content="email=no" name="format-detection" />//安卓将不识别邮箱
26.消除transition闪屏
.css {
-webkit-transform-style: preserve-3d;
-webkit-backface-visibility: hidden;
-webkit-perspective: 1000;
}
开启硬件加速
解决页面闪白
保证动画流畅
.css {
-webkit-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0);
-ms-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
设计高性能CSS3动画的几个要素
尽可能地使用合成属性transform和opacity来设计CSS3动画,
不使用position的left和top来定位
利用translate3D开启GPU加速
27.手机拍照和上传图片
/**IOS有拍照、录像、选取本地图片功能,*部分Android只有选择本地图片功能。*Winphone不支持*/
<input type="file" accept="images/*" />
28.页面切换动画?
react-addons-css-transition-group
29.移动端如何清除输入框内阴影
在iOS上,输入框默认有内部阴影,但无法使用box-shadow来清除,如果不需要阴影,可以这样关闭:
input,
textarea {
border: 0;
-webkit-appearance: none;
}
30.屏幕旋转的事件和样式
<!-- uc强制竖屏 --><meta name="screen-orientation" content="portrait">
<!-- QQ强制竖屏 --> <meta name="x5-orientation" content="portrait">
window.orientation,取值:正负90表示横屏模式、0和180表现为竖屏模式;
window.onorientationchange = function(){
switch(window.orientation){
case -90:
case 90:
alert("横屏:" + window.orientation);
case 0:
case 180:
alert("竖屏:" + window.orientation);
break;
}
}
样式
//竖屏时使用的样式
@media all and (orientation:portrait) {
.css{}
}
//横屏时使用的样式
@media all and (orientation:landscape) {
.css{}
}
webview难以强制控制竖屏
31.audio元素和video元素在ios和andriod中无法自动播放
应对方案:触屏即播
$('html').one('touchstart',function(){
audio.play()
})
32.摇一摇功能
HTML5 deviceMotion:封装了运动传感器数据的事件,可以获取手机运动状态下的运动加速度等数据。
33. web识别移动端的设备
var userAgentInfo = navigator.userAgent;
var Agents = new Array("Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod");
或者
const ua = window.navigator.userAgent.toLocaleLowerCase();
const isIOS = /iphone|ipad|ipod/.test(ua);
const isAndroid = /android/.test(ua);
const isMiuiBrowser = /miuibrowser/.test(ua);
34.web后台锁屏息屏监听
window.resize
visibilitychange可以监听手机锁屏和浏览器切换到后台的动作。fidder抓包debugger
35.如何解决盒子边框溢出
-webkit-box-sizing:border-box;
当你指定了一个块级元素时,并且为其定义了边框,设置了其宽度为100%。在移动设备开发过程中我们通常会对文本框定义为宽度100%,将其定义为块级元 素以实现全屏自适应的样式,但此时你会发现,该元素的边框(左右)各1个像素会溢了文档,导致出现横向滚动条,为解决这一问题,我们可以为其添加一个特殊 的样式-webkit-box-sizing:border-box;用来指定该盒子的大小包括边框的宽度。
36.websocket
websocket是HTML5的一个新协议,它允许服务端向客户端传递信息,实现浏览器和客户端双工通信。websocket弥补了HTTP不支持长连接的特点。
websocket+echarts可能产生内存泄漏问题,可以通过clear()在更新内容锁定缩放,定位位置,离开组件时dispose()解决
var ws;
/**
* 连接 websocket
* @param func onopen要执行的函数,可以为空
*/
function ws_connect(func) {
ws = new WebSocket("ws://" + ws_ip);
// 服务端主动推送消息时会触发这里的 onmessage
ws.onmessage = function (e) {
console.log('ws_onmessage ');
};
ws.onopen = function (e) {
console.log('ws_onopen');
// 开启心跳
ws_heart();
if (typeof func == 'function') {
func();
}
};
ws.onerror = function (e) {
console.error("ws_onerror:", e);
};
ws.onclose = function (e) {
console.log('ws_onclose:code:' + e.code + ';reason:' + e.reason + ';wasClean:' + e.wasClean);
};
}
$(function () {
var func = function () {
var data = {type: 'login'};
ws.send(JSON.stringify(data));
};
// 页面加载时第一次连接,也可以传空
ws_connect(func);
});
————————————————
断线重连
重新连接的时候 Websocket 的属性 readyState 有着至关重要的作用,先了解一下这个属性的含义(以下其中之一):
0 (CONNECTING)
正在链接中
1 (OPEN)
已经链接并且可以通讯
2 (CLOSING)
连接正在关闭
3 (CLOSED)
连接已关闭或者没有链接成功
除了第一次连接,每一次连接时都必须考虑当前的连接状态,比如我要执行 ws.send(data); ,在四种状态下的执行时机是不同的,如下:
0 (CONNECTING)
正在链接中 - 等连接成功后,在 ws.onopen 里执行
1 (OPEN)
已经链接并且可以通讯 - 直接执行就是了
2 (CLOSING)
连接正在关闭 - 等关闭完成后,在 ws.onclose 里重新连接,在重连成功的 ws.onopen 里执行
3 (CLOSED)
连接已关闭或者没有链接成功 - 重新连接,在重连成功的 ws.onopen 里执行
这样每次发送数据都能保证连接成功(除非网络断了或服务器挂了),写一个函数 ws_execute() 封装这些操作,这个函数如下:
/**
* 根据连接状态单线程连接 websocket
* @param func onopen要执行的函数,可以为空
*/
function ws_execute(func) {
console.log('ws_execute:readyState:' + ws.readyState);
if (ws.readyState == 0) {
// 正在链接中
var _old$open = ws.onopen;
ws.onopen = function (e) {
// 原本 onopen 里的代码先执行完毕
_old$open.apply(this, arguments);
if (typeof func == 'function') {
func();
}
};
} else if (ws.readyState == 1) {
// 已经链接并且可以通讯
if (typeof func == 'function') {
func();
}
} else if (ws.readyState == 2) {
// 连接正在关闭
var _old$close = ws.onclose;
ws.onclose = function (e) {
// 原本 onclose 里的代码先执行完毕
_old$close.apply(this, arguments);
ws_connect(func);
};
} else if (ws.readyState == 3) {
// 连接已关闭或者没有链接成功
ws_connect(func);
}
}
————————————————
业务逻辑里发送数据是这样的(代码片断):
// 发送数据时,将代码构造成函数作为参数,等 onopen 时执行
var func = function () {
var data = {type: 'audio'};
ws.send(JSON.stringify(data));
};
ws_execute(func);
————————————————
心跳
有了上面的 ws_execute() 函数,心跳就简单了,比如每1分钟向服务器发送一次数据:
var ws_heart_i = null;
/**
* websocket 每1分钟发一次心跳
*/
function ws_heart() {
if (ws_heart_i) clearInterval(ws_heart_i);
ws_heart_i = setInterval(function () {
console.log('ws_heart');
var func = function () {
var data = {type: 'ping'};
ws.send(JSON.stringify(data));
};
ws_execute(func);
}, 60000);
}
————————————————