实用/优秀的代码写法
- es6 数组Array支持链式编程,例子身份证中间几位用'*'代替,替代了我组长说的substr的基础写法。
let identity = '4406831112333456675X';
let result = Array.from(identity).map((v, i) => {
return (i >= 2 && i < 10 ? '*' : v);
}).join('');
- es6 ...操作符,做合并数组,伪数组转真数组 es6 扩展运算符 三个点(...)
const data = [{a: 1},{b: 2}],
copy = [ ...data ],
c = data;
console.log(data === copy); // false
console.log(data === c); // true
[...data, ...copy]; // [{a: 1},{b: 2},{a: 1},{b: 2}]
- 三目运算符计算多种情况
应用场景:同一个div通过三种不同的字符显示三种不同的背景色,只能在view层写(不能用if)
function setColor(v){
return v!==2?(v===3?'blue':(v===1?'green':'white')):'red';
}
console.log(setColor(1),setColor(2),setColor(3),setColor(4),setColor(5))
- 两个数组合并成成一个数组并以对象的形式一一对应(Array.reduce解决合并思路)
注意,return用逗号隔开只返回最后一个值
var rs = {
head: ["id", "name"],
data: [ [100, "Tom"], [101, "Jane"] ]
};
// 转换为[{"id":100,"name":"Tom"},{"id":101,"name":"Jane"}]
console.log(JSON.stringify(normalize(rs)));
function normalize (rs) {
return rs.data.map(dataItem =>
rs.head.reduce((itemResult, itemKey, curIndex) =>
((itemResult[itemKey] = dataItem [curIndex]), itemResult)
// 只返回itemResult,这里运算两次但只要逗号后面的结果
, {})
);
}
- 利用Object.definedProperty进行双向数据绑定,核心访问器(get,set),vue就是利用这种方式绑定数据.
set();一旦属性被重新赋值,此方法被自动调用。
get();一旦属性被访问读取,此方法被自动调用。
<label>输入:</label><input type="text" id="demo1"><br/>
<label>输出:</label> <input type="textarea" id="demo2"></input>
<script>
let a={};
let output=[];
Object.defineProperty(a,'b',{ //给a对象添加b属性
set:function(val){
output['b']=val;
},
get:function(){
return output['b'];
}
})
let demo1=document.querySelector('#demo1');
let demo2=document.querySelector('#demo2');
demo1.onkeyup=function(){
a.b=demo1.value;//给a对象添加b属性时候,触发了a的set方法,此时#demo1的value值赋值给output['b']。
demo2.value=output['b'];
}
</script>
- 在ng2中自定义了一个路由拦截的服务并在其设置方法,通过数据库返回的每个账号的登录权限(实际就是记录能访问的路由地址保存在routePath)。下面Array.some(callback)(筛选地址数组this.permissions每一个值,是否与callback的return值相等,有一个相等都返回true)和String.prototype.includes(string)(字符串是否包含指定的字符串返回true/false)配合使用,来判断是否有权限访问
/**
* 验证是否有该路由的权限
* @param url
*/
AuthGuardService.prototype.validPermissions = function (routePath) {
return this.permissions.some(function (url) {
return routePath.includes(url);
});
};
- 在app做搜索的时候,遇到历史记录要做去重操作,ES6提供了新的数据结构Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。学习地址
Set结构的实例有以下属性。
Set.prototype.constructor:构造函数,默认就是Set函数。
Set.prototype.size:返回Set实例的成员总数。类似数组的length
Set实例的方法分为两大类:操作方法(用于操作数据)和遍历方法(用于遍历成员)。下面先介绍四个操作方法。
add(value):添加某个值,返回Set结构本身。
delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
has(value):返回一个布尔值,表示该值是否为Set的成员。
clear():清除所有成员,没有返回值。clear()
遍历方法
keys():返回一个键名的遍历器
values():返回一个键值的遍历器
entries():返回一个键值对的遍历器
forEach():使用回调函数遍历每个成员
// Set去重返回的是伪对象{0:{},1:{},length:2}
obj.content = Array.from(new Set(obj.content));
- 当后端返回字符串,前端要根据对应的字符串取下标志控制样式或者什么的,可以用简单的枚举
enum Index { '未处理', '处理中', '已处理', '否决' };
this.dealIndex = +Index[this.detailJson['abnoHandleStsName']];
-
同源页面通信通过监听本地存储storage的变化,去改变页面状态。例子当主页先从接口保存数据,然后打开一个同源不同路由的页面,该页面相当于一个新的资源文件,不会监听到其他同源页面对全局变量,异步事件传发的状态改变的值,只能通过localstorage去通信。
window.addEventListener('storage', _ => {
this.isLoad = false;
this.data = JSON.parse(localStorage.getItem('logChat'));
})
- (ES7新语法async await)表格系统一般具有导出功能,前端导出一般只会导出当前html上有的东西,后端导出可以按需导出数据(全部数据等)。实际业务中表格会出现几万条甚至更多的表格数据,全部导出就会调用接口并传导出的条数作为参数,当后端服务器压力大的时候,用户还继续导出全部数据如({'rows': 9999999}),服务器就可能崩溃了。作为前端可以做的是分次查询导出接口,而不是一次传9999999这种极端参数。
/**
* 同步导出每次查询的结果
*/
async exportHandler($event) {
let params = {"first": 0, "rows": 100};
if (PageInfo.totalPages > 1) {
try {
for (var i = 1; i < PageInfo.totalPages; i++) {
params.first = params.rows * i; // 计算页数
let content = await this.qryExportData(params, i);//async await类似promise处理地狱回调的效果
//这里不走完下面是不会执行的
PageInfo.totalContent = PageInfo.totalContent.concat(content);
}
} catch (e) {
$event.done(null, null, true);
this.msgs = this.tips.error('导出查询失败!');
}
}
$event.done($event.grid, PageInfo.totalContent);
}
-
input[type=file]选择同一个文件只触发一次,原因在于onChange事件同一个文件,不停的选择,只会触发一次。
解决方法:
1、不用change。在JS事件监听选择事件替代。
2、用change,但是上传成功后,清除file input 选择的内容。下次就可以选择同样文件
event.target.value = ""; //清空目标文件
-
获取元素占据页面的所有矩形区域 document.documentElement.getBoundingClientRect
好处:比用style去获取更高级的方法,在TS中直接这样写超爽
const {top, left} = document.documentElement.getBoundingClientRect();
//IE8以下获取的是一个数组,兼容方法 document.documentElement.getBoundingClientRect()[0];
-
当面对不能用position的情况去定位的时候,使用CSS3 calc 和 vh单位 去计算高度配合
注:这个插件被JS代码控制了定位相关的css样式,无奈只能用css3,注意兼容性 div 底部固定方法(不用position定位)
Angular2的注意地方
- 模板变量不能与ngModel的名称相同,不然会报一个Cannot assign to a reference or variable!(不能赋值给引用或变量!),以下写法就跪在了这个错误,模板变量可以写多个
<textarea #cancelText placeholder="请输入原因" name="cancelModel" [(ngModel)]="cancelText"></textarea>
- Component/Pipe/Directive等只能在一个module引入一次,不然会报一个多次引入Component的错误,但由于一个组件有可能用到不同的模块下的页面,每个页面又有自己的module(ionic3懒加载必须每个页面都有module),解决的办法在对应的公共 XxComponent.ts文件下注入@NgModule并导出该公共组件的Module。如果公共组件多可以在公共组件文件夹下创建一个Module文件,把所有Component都导入进去。因为module可以引入多次
- ng-template和ngIf 请看zorro用法 @ContentChild('nzOptionTemplate') nzOptionTemplate;
// 1
<ng-template [ngIf]="true">123</ng-template> // 页面会正常显示123
// 2
<ng-content></ng-content>//当使用@ContentChild('content')装饰器,可以获取下面123的值放进页面,尽管ngIf=false
<ng-template #content [ngIf]="false">123</ng-template>
-
Using useExisting provider(元数据providers添加useExisting配合抽象类,提高代码可读性同时提升代码编译速度,因为在编译组件过程中会把注入的服务全部编译放在组件类里)
-
angular4+ 有时候更改了部分组件或文件,通过AOT打包上去后还是出现浏览器缓存问题,尝试直接在script标签加上hash值作强制修改文件名的方法,会导致项目上线后,用户通过地址打开网站新文件并没有更新上去,而是要再刷新一次才会请求服务器拉去最新代码文件。具体原因未知
其他
- 最近写公司组件文档https://1ziton.github.io/primeng-ext/,发现import/export在项目中的一种用法。我们一般会把所有的公共组件都写成各自的模块整理在一个文件夹里,写成模块是为了方便不同的地方调用避免因declarations 2 component的错误。同时我们只向外提供一个接口(路径,所有公共组件都导入导出到此),让外来文件导入所需的公共组件只需在这个接口上面找就可以了,下面就是向外提供的接口模块,import是为了统一管理模块,export是为了供外界使用。这里需要注意的地方,primeng-ext这些公共组件有可能被其他公共组件导入使用,这里我们就不可以这样导入,原因是循环引用了,custom-component.module.ts导入你的业务模块,你的业务模块又导入custom-component.module.ts里边的东西。会出现module找不到的情况
import { AutoCompleteModule } from "app/custom-components/custom-components.module";
// ---------------------------------------------------------
// | Imports
// ---------------------------------------------------------
// Common of angular
import { NgModule, ModuleWithProviders } from '@angular/core';
//share module
import { CommonModule } from "@angular/common";
import { FormsModule } from "@angular/forms";
import { HttpModule } from "@angular/http";
// primeng
import { DataTableModule } from "app/components/datatable/datatable";
//...
//primeng-ext
import { AutoCompleteModule } from "./_primeng-ext/autocomplete";
import { FileUploadModule } from "./_primeng-ext/fileupload";
import { UICalendarModule } from "./_primeng-ext/calendar/calendar";
// Modules
import { AreaSelectComponent } from "app/custom-components/area-select/area-select.component";
import { AbnormalMoverComponent } from "app/custom-components/abnormal-mover/abnormal-mover-select.component";
//...
// ---------------------------------------------------------
// | Exports
// ---------------------------------------------------------
// Modules
//primeng-ext
export { AutoCompleteModule } from "./_primeng-ext/autocomplete";
export { FileUploadModule } from "./_primeng-ext/fileupload";
export { UICalendarModule } from "./_primeng-ext/calendar/calendar";
// Components
export { EchartsDirective, EchartsModule } from "app/custom-components/echarts/echarts";
export { AreaSelectComponent } from "app/custom-components/area-select/area-select.component";
//...
// Services
export { API } from "app/custom-components/services/api";
// Tokens (eg. global services' config)
// ---------------------------------------------------------
// | Root module
// ---------------------------------------------------------
@NgModule({
imports: [
HttpModule,
CommonModule,
FormsModule,
DataTableModule,
TreeModule,
//...
],
declarations: [
UIUpload,
AreaSelectComponent,
//...
],
exports: [
UICalendarModule,
UIGridModule,
UIUpload,
UISelectBoxModule,
//...
],
providers: [
AreaService
]
})
export class CustomComponentsModule {
}
- 利用H5新东西Bolb对象,blob 存储着大量的二进制数据,并且 blob 的 size 和 type 属性,都会被 file 对象所继承。项目中用blob作导出excel表的功能
。在这里不是说blob怎么用,而是导出的excel有时候会乱码,具体下图收货人号码new Blob([csv], {type: 'text/csv;charset=utf-8;'});
解决方法:基于primeNG datatable的源码扩展的对每个单元格内的值进行转换,下图
csv +='"' + value + '\ufeff"'; 就是解决某些单元格乱码的关键,excel不会因为数据是字符就会自动用文本形式显示。
data.forEach(function (record, i) {
csv += '\n';
for (var i_1 = 0; i_1 < columns.length; i_1++) {
if (columns[i_1].field && !columns[i_1].hidden) {
let value = _.get(record, columns[i_1].field, null);
if (typeof value === 'string') {
alue = value.replace('"', '""');
} else if (value === null || value === 'null' || value === 'undefined') {
value = "";
}
csv += '"' + value + '\ufeff"';
if (i_1 < (columns.length - 1)) {
csv += ",";
}
}
}
});