1 2 3 4 5 6 7 8 9 10 11 12 |
/** * 如果target(也就是FirstOBJ[key])存在, * 且是对象的话再去调用deepObjectMerge, * 否则就是FirstOBJ[key]里面没这个对象,需要与SecondOBJ[key]合并 */ function deepObjectMerge(FirstOBJ, SecondOBJ) { // 深度合并对象 for (var key in SecondOBJ) { FirstOBJ[key] = FirstOBJ[key] && FirstOBJ[key].toString() === "[object Object]" ? deepObjectMerge(FirstOBJ[key], SecondOBJ[key]) : FirstOBJ[key] = SecondOBJ[key]; } return FirstOBJ; } |
分类:前端
JS判断当前DOM树是否加载完毕
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
/** * @function Monitor whether the document tree is loaded. * @param fn */ function domReady(fn) { if (document.addEventListener) { // 标准浏览器 document.addEventListener('DOMContentLoaded', function () { //注销时间,避免重复触发 document.removeEventListener('DOMContentLoaded', arguments.callee, false); fn(); // 运行函数 }, false); } else if (document.attachEvent) { // IE浏览器 document.attachEvent('onreadystatechange', function () { if (document.readyState == 'complete') { document.detachEvent('onreadystatechange', arguments.callee); fn(); // 函数运行 } }); } } domReady(loadStart); |
被引用的外部JS存在window.onload时,判断当前页面是否已存在window.onload,并进行相应处理
JS Cookie相关操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
function setCookie(cookieName, cookieValue, expires) { // 设置Cookie function getCookieName(cookieName) { //获取并返回与 cookieName 同名的 cookie 名称,允许大小写不同,如果不存在这样的 cookie,就返回 cookieName var lowerCookieName = cookieName.toLowerCase(); //转换为小写 var cookieStr = document.cookie; // 获取当前cookie if (cookieStr == "") { return cookieName; } var cookieArr = cookieStr.split(";"); var pos = -1; for (var i = 0; i < cookieStr.length; i++) { pos = cookieArr[i].indexOf("="); if (pos > 0) { if (cookieArr[i].substring(0, pos).toLowerCase() == lowerCookieName) { return cookieArr[i].substring(0, pos); } } } return cookieName; } function writeCookie(cookieName, cookieValue, expires) { // 写cookie,不区分大小写 if (expires) { document.cookie = getCookieName(cookieName) + "=" + escape(cookieValue) + "; expires=" + expires.toGMTString(); } else { document.cookie = getCookieName(cookieName) + "=" + escape(cookieValue); } } function readCookie(cookieName, defaultValue) { //获取并返回 cookie 值,不区分大小写 var lowerCookieName = cookieName.toLowerCase(); var cookieStr = document.cookie; if (cookieStr == "") { return defaultValue; } var cookieArr = cookieStr.split("; "); var pos = -1; for (var i = 0; i < cookieArr.length; i++) { pos = cookieArr[i].indexOf("="); if (pos > 0) { if (cookieArr[i].substring(0, pos).toLowerCase() == lowerCookieName) { return unescape(cookieArr[i].substring(pos + 1, cookieArr[i].length)); } } } return defaultValue; } writeCookie(cookieName, cookieValue, expires); } |
原生ajax方法封装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
/** * @function ajax request * @fields ajaxName:请求名称,method:请求方法,headers:setRequestHeader自定义部分,url:接口地址,async:是否异步请求,withCredentials:是否支持跨域发送cookie,dataType:数据类型 ,data:post请求参数 * @param data:{ajaxName:"ajaxNameString",headers:{},method:"GET/POST",url:"",async:true/false,withCredentials:true/false,dataType:"json",data:""} * @result ajaxName.responseText */ function ajaxRequest (data, callback) { data = data || {} data.dataType = data.dataType || 'json' var sendParams = null var headers = data.headers || {} var ajax = data.ajaxName // 新建请求 if (window.XMLHttpRequest) { ajax = new XMLHttpRequest() } else { ajax = new ActiveXObject('Microsoft.XMLHTTP') } // 打开请求 ajax.open(data.method.toUpperCase(), data.url, data.async) // 是否支持跨域发送cookie ajax.withCredentials = data.withCredentials ajax.setRequestHeader("Content-type", data.contentType || "application/x-www-form-urlencoded") // POST请求设置 if (data.method == 'POST') { for (var i in headers) { ajax.setRequestHeader(i, headers[i]) } if (data.data) { sendParams = data.data } } // 发送请求 ajax.send(sendParams ? sendParams : null) // 注册事件 ajax.onreadystatechange = function () { if (window.location.origin + '/login/index' === ajax.responseURL) { window.location.reload() window.location.href = window.location.origin + '/login/index' return } callback(ajax) } } /** * GET * @param ajaxName 请求名称 * @param requestUrl 请求接口地址 * @param async 是否异步请求 * @param callBack 回调函数 * @param contentType 请求类型 */ function ajaxGetData (ajaxName, requestUrl, async, callBack, contentType) { ajaxRequest({ ajaxName: ajaxName, contentType: contentType || "application/json;charset=utf-8", method: "GET", url: requestUrl, async: async, cache: false, withCredentials: true, dataType: "json" }, function callback (ajax) { if (ajax.status == 200 && ajax.readyState == 4) { callBack(ajax.responseText) } }) } /** * 拼接GET请求url参数 * @param url * @param params * @returns {string} */ function formateGetUrl (url, params) { var resultParams = '' for (var key in params) { resultParams = resultParams + '&' + key + '=' + params[key] } return url + '?' + resultParams.substr(1) } /** * POST * @param ajaxName 请求名称 * @param requestUrl 请求接口地址 * @param async 是否异步请求 * @param callBack 回调函数 * @param contentType 请求类型 */ function ajaxPostData (ajaxName, requestUrl, params, async, callBack, contentType) { var resultParams = '' if (!contentType || contentType === "application/x-www-form-urlencoded;charset=utf-8") { for (var key in params) { resultParams = resultParams + '&' + key + '=' + encodeURIComponent(params[key]) } } else { resultParams = params && JSON.stringify(params) } ajaxRequest({ ajaxName: ajaxName, headers: {}, contentType: contentType || "application/x-www-form-urlencoded;charset=utf-8", method: "POST", dataType: "json", url: requestUrl, processData: true, async: async, data: resultParams }, function callback (ajax) { if (ajax.status == 200 && ajax.readyState == 4) { callBack(ajax.responseText) } }) } |
JS格式化时间(支持小程序,兼容IOS)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
const REGEX = /(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})/ /** * @function format time * @param val, format * @return {string} * @example * <template> * <div> * <span>{{item.time | formatTime('yyyy/MM/dd hh:mm:ss')}}</span> * </div> * </template> * import {formatTime} from '../../library/timeFormat' * export default { * filters: {formatTime} * } */ export const formatTime = (val, format) => { if (val) { /** * @instructions 如果不是时间戳格式,且含有字符 '-' 则将 '-' 替换成 '/' && 删除小数点及后面的数字 * @reason 将 '-' 替换成 '/' && 删除小数点及后面的数字 的原因是safari浏览器仅支持 '/' 隔开的时间格式 */ if (val.toString().indexOf('-') > 0) { val = val.replace(/T/g, ' ').replace(/\.[\d]{3}Z/, '').replace(/(-)/g, '/') // 将 '-' 替换成 '/' val = val.slice(0, val.indexOf('.')) // 删除小数点及后面的数字 } let date = new Date(val) date.setHours(date.getHours() + 8) const [whole, yy, MM, dd, hh, mm, ss] = date.toISOString().match(REGEX) const year = new Date().getFullYear() const month = new Date().getMonth() + 1 const dates = new Date().getDate() if (format) { return format .replace('yyyy', yy) .replace('yy', yy.slice(2)) .replace('MM', MM) .replace('dd', dd) .replace('hh', hh) .replace('mm', mm) .replace('ss', ss) } else { return [yy, MM, dd].join('-') + ' ' + [hh, mm, ss].join(':') } } else { return '--' } } |
理解[].forEach.call()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
例子: let cols = document.querySelectorAll('ul li') [].forEach.call(cols, function (col, index) { // TODO } 分析: ① []是一个空数组,无论这个数组里的最初值是什么,它们都不会被使用到; ② forEach方法是一个数组方法,只有数组才能调用;完整写法:Array.prototype.forEach,Array.forEach为简写; ③ call方法: 语法:fun.call(thisArg, arg1, arg2, ...) 参数:thisArg:在 fun 函数运行时指定的this值; arg1, arg2, ... : 指定的参数列表; 综上:[]这个空数组里的值(当然,它没有值)是最初的this值,通过call方法,当这个空数组调用方法forEach时, cols里的值会取代空数组原先的this值。 通俗的说,就是cols需要使用forEach这个方法, 但是这个方法是一个数组方法,只有数组才能调用,于是通过call方法来了个偷梁换柱, 在数组调用forEach方法的时候,将数组里的this值替换成了cols的值,达成了目的。 |
解决React首屏加载白屏的问题
Cannot resolve symbol ‘Component’ & Cannot resolve symbol ‘PropTypes’
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import React, { Component, PropTypes } from 'react' 报错:Cannot resolve symbol 'Component' Cannot resolve symbol 'PropTypes' 1.解决 Cannot resolve symbol 'Component' 安装依赖:npm install @types/react --save 调用方法:import React, { Component } from 'react' 2.解决 Cannot resolve symbol 'PropTypes' 安装依赖:npm install prop-types --save 调用方法:import PropTypes from 'prop-types' 注:React.PropTypes 自 React v15.5 起已弃用。请使用 prop-types 库代替。 |
React & Redux 的一些基本知识点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
一、React.createClass 跟 React.Component 的区别在于后者使用了ES6的语法,用constructor构造器来构造默认的属性和状态。 1. React.createClass import React from 'react'; const Contacts = React.createClass({ render() { return ( <div></div> ); } }); export default Contacts; 2.React.Component import React from 'react'; class Contacts extends React.Component { constructor(props) { super(props); } render() { return ( <div></div> ); } } export default Contacts; 二、 Super(props) 调用父类的构造函数,react希望把所有props,state的定义尽量放到父类中进行。 子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类没有自己的this对象, 而是继承父类的this对象,然后对其进行加工。如果不调用super方法,子类就得不到this对象。 三、容器组件 Container Components 和展示组件 Presentational Components -------------------------------------------------------------------------- | 展示组件 | 容器组件 -------------------------------------------------------------------------- 作用 | 描述如何展现(骨架、样式) | 描述如何运行(数据获取、状态更新) -------------------------------------------------------------------------- 直接使用Redux | 否 | 是 -------------------------------------------------------------------------- 数据来源 | props | 监听 Redux state -------------------------------------------------------------------------- 数据修改 | 从 props 调用回调函数 | 向 Redux 派发 actions -------------------------------------------------------------------------- 调用方式 | 手动 | 通常由 React Redux 生成 -------------------------------------------------------------------------- <strong>四、connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])</strong> 连接 React 组件与 Redux store。连接操作不会改变原来的组件类,而是返回一个新的已与 Redux store 连接到组件类。 1.[mapStateToProps(state, [ownProps]): stateProps] (Function): 如果定义该参数,组件将会监听 Redux store 的变化。只要 Redux store 发生变化,mapStateToProps函数就会被调用。 该回掉函数必须返回一个纯对象,这个对象与组件的props合并。如果省略了这个参数,组件将不会监听 Redux store。 如果指定了第二个参数 ownProps,则该参数的值为传递到之间的props,而且只要组件接收到新的 props, mapStateToProps也会被调用。 2.[mapDispatchToProps(dispatch, [ownProps]): dispatchProps] (Object or Function): 如果传递的是一个对象,那么每个定义在该对象的函数都将被当作 Redux action creator, 对象所定义的方法名将作为属性名;每个方法将返回一个新的函数,函数中dispatch方法会将action creator的返回值作为参数执行。 这些属性会被合并到组件的 props 中。如果传递的是一个函数,该函数将接收一个 dispatch 函数,然后由你来决定如何返回一个对象, 这个对象通过 dispatch 函数与 action creator 以某种方式绑定在一起(提示:你也许会用到 Redux 的辅助函数 bindActionCreators())。 如果你省略这个 mapDispatchToProps 参数,默认情况下,dispatch 会注入到你的组件 props 中。 如果指定了该回调函数中第二个参数 ownProp该参数的值为传递到组件的 props,而且只要组件接收到新 props,mapDispatchToProps 也会被调用。 3.[mergeProps(stateProps, dispatchProps, ownProps): props] (Function): 如果指定了这个参数,mapStateToProps() 与 mapDispatchToProps() 的执行结果和组件自身的 props 将传入到这个回调函数中。 该回调函数返回的对象将作为 props 传递到被包装的组件中。你也许可以用这个回调函数,根据组件的 props 来筛选部分的 state 数据, 或者把 props 中的某个特定变量与 action creator 绑定在一起。如果你省略这个参数,默认情况下返回 Object.assign({}, ownProps, stateProps, dispatchProps) 的结果。 4.[options] (Object): 如果指定这个参数,可以定制 connector 的行为。 [pure = true] (Boolean): 如果为 true,connector 将执行 shouldComponentUpdate 并且浅对比 mergeProps 的结果, 避免不必要的更新,前提是当前组件是一个“纯”组件,它不依赖于任何的输入或 state 而只依赖于 props 和 Redux store 的 state。默认值为 true。[withRef = false] (Boolean): 如果为 true,connector 会保存一个对被包装组件实例的引用, 该引用通过 getWrappedInstance() 方法获得。默认值为 false。 |