StepByStep高频面试题深入解析-周刊07

不积跬步无以至千里。 关于【Step-By-Step】Step-By-Step (点击进入项目) 是我于 2019-05-20 开始的一个项目,每个工作日发布一道面试题。每个周末我会仔细阅读大家的答案,整理最一份较优答案出来,因本人水平有限,有误的地方,大家及时指正。 如果想 加群 学习,可以通过文末的公众号,添加我为好友。 __ 本周面试题一览:实现一个 JSON.stringify实现一个 JSON.parse实现一个观察者模式使用CSS让一个元素水平垂直居中有哪些方式ES6模块和CommonJS模块有哪些差异?31. 实现一个 JSON.stringifyJSON.stringify([, replacer [, space]) 方法是将一个JavaScript值(对象或者数组)转换为一个 JSON字符串。此处模拟实现,不考虑可选的第二个参数 replacer 和第三个参数 space,如果对这两个参数的作用还不了解,建议阅读 MDN 文档。 JSON.stringify() 将值转换成对应的 JSON 格式:基本数据类型: undefined 转换之后仍是 undefined(类型也是 undefined)boolean 值转换之后是字符串 "false"/"true"number 类型(除了 NaN 和 Infinity)转换之后是字符串类型的数值symbol 转换之后是 undefinednull 转换之后是字符串 "null"string 转换之后仍是stringNaN 和 Infinity 转换之后是字符串 "null"如果是函数类型 转换之后是 undefined如果是对象类型(非函数) 如果有 toJSON() 方法,那么序列化 toJSON() 的返回值。如果是一个数组 - 如果属性值中出现了 `undefined`、任意的函数以及 `symbol`,转换成字符串 `"null"`如果是 RegExp 对象。 返回 `{}` (类型是 string)如果是 Date 对象,返回 Date 的 toJSON 字符串值如果是普通对象; ...

July 10, 2019 · 5 min · jiezi

微前端改造初探

在写这篇文章的一个多月前,本坑还不知道微前端是什么,大概从字面上的含义是比较小的前端项目。 本坑开始实践它,是由于工作要求。改造一个运行多年,前端用jsp写的服务平台项目(以下简称该平台)。改造它是改造它的前端架构。改造它的原因是比较多人反馈,其页面加载和渲染显得吃力,页面切换后首屏等待时间长的问题,交互体验舒适度不可避免的下降了,特别是在老式电脑面前。 该平台业务比较多,所以组长希望前端框架组能把平台中的前端部分分离出来,最好用当下满大街的Vue、能够按照各个一级菜单分成若干前端子项目,用户访问依然是整体的项目,同时这一改造实施过程不需要重做一个、而是整个500多个页面从局部开始、是逐步、兼容的,新旧同时运行,直至整体被替换。(ps:不重做?这......科学吗?) 看看,慢在哪里其实大概知道慢在哪里,但是不知道究竟慢在具体哪个部分。和其他一以贯之的类似管理平台布局并无不同。左边导航栏,上面顶栏,右侧内容栏,整体页面是一个index.jsp。上面提到的内容栏是一个iframe,里面通过切换src来切换页面。更多的业务造就更多页面,更多页面带来更多的加载。加上长时间没有做好资源加载的管理,导致渲染一次页面需要加载大量js,css或者多次加载同一个文件的情况。该平台大量的配置页面生成,是通过easyui的来做的。通过数据来创造整个页面dom节点,也拖累了内容完整呈现的时间。 我们使用谷歌浏览器performance可以最终追查到这个系统在哪些方面,哪个方法存在着哪些延迟。结论是: 1、混乱的项目资源管理导致大量的资源请求。 2、easyui和项目中不少的dom操作带来大量的重排和重绘。 3、埋点,插件使用不当以及其他。 微前端它是什么呢? 微前端的概念来自于之前流行的微服务。它的来源很大程度是来自于这篇文章 。微服务系统使得后台服务架构能够比较好地规避越来越臃肿的体积带来的性能下降。根据业务合理拆分成一个个的服务,尽量避免一个子服务影响整个项目运行的优势,有效的进行隔离。 那么,前端也有同样的需求吗?答案是肯定的。 今天,日益更新的前端技术,已经能够把一个个页面各个小元素打包成组件库,功能包,在多个项目中引入使用。此外,我们不用再使用难受的iframe来聚合不同的项目,而是导出一个个web component,只需要import 到页面就可以使用。把一个个子项目打包成一个个web component,聚合在入口项目之内。这也许就是微前端现在比较时髦的样子。如果一个大项目有以下特点,微前端可以在这些项目中运用:1、大项目有统一的入口,子项目页面需要无刷新下切换,可是各个子项目在业务上和开发团队上是不同的。 2、项目过大,打包、运行、部署效率出现显著下降的问题。这时希望能根据业务拆分打包,部署。 方案与实施回到本文开头,一开始面对这样的需求还是有些想辞职的冲动,因为觉得需求有点不是符合实际,实际上要实施改版也是需要过程的。 不过静下来想想,搜搜,翻了翻当前项目的前端结构,隐隐约约似乎浮现一些需求可行性的线索。 因为项目的最终目的是把整个jsp页面改成vue来写。而这一要求是逐步替换的过程,所以在改造过程中,同时要保证项目兼容jsp的页面。我们继续沿用了原来就有的iframe,借此把jsp融入整个微前端框架,而已经改造的micro则不需要iframe.我们的开发团队,分框架组和各个业务组。其中每个业务组有3到8个人,他们大多数是后端背景,主要做的也是后端开发。框架组有前端和后端。为了应付庞大的业务开发需求。大部分后端人员都需要使用jsp,js等前端技术进行开发。框架组为了减少他们的前端开发门槛,前端框架组会封装好easyui组件,提供业务组使用。所以,正如前文提到,后端人员是通过数据,结合框架组提供的组件来完成页面的开发的。从某种角度来说,数据配置的页面对接下来的改造工作有一定的帮助,因为大部分页面可以同时改写。 我们对整个项目进行了大致的分类。 1、portal 项目:该项目是整个微前端项目的入口。里面含有loader,用以加载各个项目模块。它也嵌入到子项目中,使得单独运行子项目和portal项目一样的界面要求。2、permission 项目:该项目包含菜单组件,登录页面,顶栏组件,权限控制等。在任何环境下,它都必须首先加载,为子项目模块挂载提供锚点。3、common项目:该项目包含公共业务组件。比如封装好的页面,可以直接给不太能够掌握vue项目的后端人员更加友好的去使用。4、业务项目:就是指业务组各个模块开发的前端项目。什么样的业务分为一个项目,这点由产品和技术人员一起来决定。相对于portal项目,业务项目相当于它的子项目。 前端框架组必须提供一套统一的业务项目的前端模板,可以在确认新建的子项目后迅速的加入到整个项目中,进行开发和部署,而这一过程不能影响其他项目的部署和运行。 除了上述方案浮出水面,还会在改造过程中遇到一个个细节问题。 不过在大方向,框架组成上,前端结构上做好了,细节问题也会随耐心和时间被解决。 分别阐述本坑根据以上的分类,大致进行说明其实现。这其中结合了不少前辈之经验,在文章结尾处鸣谢。 Portal:portal 项目是整个项目部署的入口,它的核心来自于single-spa 在整个项目结构中它将集成到每一个子项目。集成的方式很粗暴简单,就是外联加载。portal负责根据不同的环境来对应的组件和app,同时也安装各个app,卸载各个app等,它负责app在single-spa的生命周期。比如集成模式下根据环境和路由加载对应的app,而在子项目运行时只加载公共组件和不同业务的app。 那么protal是如何加载的呢? protal维护了一个json里面包含了各个子项目的index.html的信息,通过匹配index.html里面的src 、link,加载各项资源。 module.exports = { common: { webName:'common', globalVarName: 'mfe:common', componentsTarget: '/common/release/components/web.html', resourcePatterns: ['/components.[0-9a-z]{8}.js/g'], loadType:'before' }, permission: { webName:'permission', globalVarName: 'mfe:permission', // URL 匹配模式 matchUrlHash: '', // 微前端地址 componentsTarget: '/permission/release/components/web.html', webTarget:'/permission/release/web/web.html', // 资源匹配模式 resourcePatterns: ['/common.[0-9a-z]{8}.css/g','/store.[0-9a-z]{8}.js/g', '/publicPath.[0-9a-z]{8}.js/g','/singleSpaEntry.[0-9a-z]{8}.js/g','/components.[0-9a-z]{8}.js/g'], //是否要在项目启动前加载,before为提前加载,after为hash变化后加载 loadType:'before' }, app4vue:{ webName:'repair-order', globalVarName: 'mfe:app4vue', matchUrlHash: '/layout/repair-order', webTarget: '/app4/release/web/web.html', resourcePatterns: ['/common.[0-9a-z]{8}.css/g','/store.[0-9a-z]{8}.js/g', '/singleSpaEntry.[0-9a-z]{8}.js/g'], loadType:'after' }} async gatherResource () { const self = this // const spaEntry = 'portal' const web = self._webName //如果是微前端聚合模式 if (window._IS_SIGLE_PORTAL) { if (web !== 'mfe-permission') { await self.loadComponents(micros.common) await self.loadApp(micros.permission) } } else { if (web === 'mfe-permission') { await self.loadComponents(micros.common) } else { if (web !== 'mfe-common') { await self.loadComponents(micros.common) } await self.loadApp(micros.permission) } } // return new Promise(resolve => resolve('loader:all Finish!')) }permisson:permission负责登录页,layout中的菜单栏,顶栏。所有的子项目app都必须挂载到permission项目中的显示区块里。也就是说permssion会提供锚点给子项目挂载。 ...

July 10, 2019 · 2 min · jiezi

Chrome-控制台常用调试技巧详解

1、Chrome控制台小技巧打开和关闭抽屉式选项卡:按Esc键可打开和关闭 DevTools 的 Drawer(抽屉式选项卡) 在Drawer(抽屉式选项卡)中,你可以在 Console 控制台中执行命令,查看动画检查器(Animations),配置网络条件(network conditions)和渲染(rendering)设置,搜索(search)字符串和文件等 使用Request blocking 阻塞请求: 使用这个功能可以拦截请求;比较常用的场景是,页面执行完某操作后页面就进行重定向跳转了,这时如果想调试重定向前发的请求做了啥,就可以使用此功能进行阻塞拦截 debugger:代码手动编程设置断点调试;Coverage 代码覆盖率检测:可以观察到代码覆盖率,哪些是没用的,去除无用代码,较少代码体积Changes 变化:显示更改代码的比较,可以通过这个工具观察你用控制台修改过的代码,类似于git 的 diff 功能类似,红色代表删除、绿色代码新增;Snippets:在 console 里可以临时运行代码,但是书写格式不太友好,而且一换行就执行了(虽然可以 shift+enter 换行),不想打开代码编辑器怎么办,可以使用 Snippets 这个工具创建js脚本,并可以访问和从任何页面的Chrome DevTools面板中执行(除非你删除)。 2、console控制台命令$_:返回最近一次计算的表达式的值;$(selector):返回匹配指定CSS选择器的第一个DOM元素的引用,实际是document.querySelector()函数的别名;$$(selector):$\$(selector)返回一个与给定CSS选择器匹配的元素数组,等效于调用document.querySelectorAll();$x(path):返回一个与给定XPath表达式匹配的DOM元素的数组;clear(): 清除控制台中所有历史记录;copy(object):将指定对象的字符串表示复制到剪贴板;debug(function):当调用指定的函数时,调试器被调用并在Sources(源文件)面板上的函数内部断点暂停;dir(object):Console API的console.dir()方法的别名。getEventListeners(object)返回在指定对象上注册事件的监听器keys(object) 返回一个数组,该数组包含属于指定对象的属性名;values(object):回一个数组,该数组包含属于指定对象的属性值;document.body.contentEditable=true:将浏览器变成编辑器monitorEvents(document.body, "click"):第一个参数是要监听的对象。如果未提供第二个参数,所有事件都会返回。要指定要监听的事件,传递一个字符串或字符串数组作为第二个参数;unmonitorEvents(document.body):停止监听body对象上的事件; 3、console API详解有开发就有console,开发调试必使用的一大命令console,看看都有些啥? (1)输出信息基本方法:console.log 用于输出普通信息console.info 用于输出提示性信息console.error用于输出错误信息console.warn用于输出警示信息console.group&&console.groupEnd分组输出,console.groupCollapsed创建新分组console.group('warn警告信息') console.warn('warn1') console.warn('warn2') console.warn('warn3')console.groupEnd()console.group('info信息') console.warn('info') console.warn('info1')console.groupEnd()console.group('log信息') console.warn('log1') console.warn('log2')console.groupEnd()console.group('error信息') console.warn('error1') console.warn('error2')console.groupEnd() 给console输出添加样式(通过背景属性图片也可以输出哦)['log','info','warn','error'].forEach(item => { let $print = console[item]; console[item] = function() { $print.call(console, '%c'+Array.prototype.slice.apply(arguments).join(' '), 'font-size: 16px;padding:10px;font-weight: bold;text-decoration: underline;') }}) (2)复杂类型输出:console.dir | console.dirxml:替代for in详细的输出对象信息,经常遇到的坑点是,使用console.log想打印出对象信息,发现只有[object Object],现在可以使用dir;dirxml如果可以会使用xml形式打印。 ...

July 9, 2019 · 1 min · jiezi

iOS多渠道统计方法解析

总所周知,iOS 是一个封闭的系统环境,当应用程序需要向外部请求或接收数据时,大部分都需要经过权限认证,否则无法获取到数据。更何况 iOS 本身就无法使用渠道包统计数据,iOS 企业签名包在上传服务器后更是难以引流下载。在这种情况下,如何给多个渠道做推广以及效果统计,是令不少开发者和运营人员头疼的问题。 从技术上,我们要实现 App Store 应用以及 iOS 企业签名包的多渠道推广效果统计。简单来说,包括各个推广渠道下用户的点击、注册、安装等运营推广数据的获取。 方案一:苹果官方统计(iTunes Connect) 在数据权威性上,苹果官方的统计工具必然最权威,也最值得信赖。 登录苹果的官方统计平台 iTunes Connect,在“App分析”模块可以很方便的查看到应用的“展示次数、购买量”等基础数据。 当然,App 推广往往需要多个渠道同时进行,由于 App Store 无法制作渠道包统计,因此 iTunes Connect 也很方便的提供了渠道链接统计服务。只需要在“App分析”的“来源”中点击“营销活动”,右上角有个“生成营销活动链接”,进入后就能自定义设置对应的唯一标识,给每个渠道生成专属的渠道链接。 拿着对应的链接去推广,虽然可以追踪到不同渠道下的精准来源,但 iTunes Connect 的统计也存在许多问题: 只有当营销活动启动后超过一天时间(最长72个小时)后才能显示相关数据;至少有 5 个 App 安装量归因于此营销活动时,营销活动才会在“App 分析”中显示;iOS 8.0 及以上版本的用户可以选择是否将自己的应用使用情况的数据发送给 Apple;iTunes Connect 的统计无法同时兼容 Android 和 iOS,采用不同的统计方法可能会让数据统一性较差。方案二:填写渠道识别码统计(邀请码/渠道码)由于苹果统计数量少时无法展示,以及数据延时性等特性,实际应用中并不适合用来统计地推、邀请有奖等 App 推广场景。 于是在业务流程上,传统做法是让用户填写渠道码来实现业绩统计,比如“老带新”活动中的填写邀请码流程、地推活动中的填写地推码流程等,其本质就是通过获取某个用户填写的专属渠道识别码,来判断用户由哪个渠道邀请来,从而统计推广业绩并发放奖励。 但这种做法会使实际推广中多出一个人工填写的操作流程,高门槛必定导致高流失,用户会产生排斥心理,推广效果也就大打折扣。 方案三:采用第三方SDK追踪以 openinstall 为例,这也是基于渠道链接统计的一种方法,与 iTunes Connect 营销活动链接统计的区别在于: 统计数据能实时反馈并显示;没有数据数量限制,无论采集的样本量多少都能实时显示;能够程序化生成海量专属渠道链接,无需人工定义渠道识别信息;可以同时统计 Android、iOS(包括企业签名) App,数据更有具统一性。同时,由于渠道链接统计的方式具有更高的灵活性,采用 openinstall 可以在不用制作渠道包、填写邀请码的情况下,识别渠道安装来源。这也意味着,开发者甚至能在业务流程上实现免填邀请码、免填地推码统计渠道业绩的需求。 另一方面,在实际应用中,由于能够程序化生成海量渠道链接的特点,可以有效解决 iOS 多渠道统计的难题,主要应用于移动广告效果统计、社交分享效果统计、iOS(包括企业签名)引流与统计、邀请层级关系的建立等方面。 总结:毋庸置疑,苹果官方统计工具在 iOS 领域必然是最优的统计方案,但客观存在的一些弊端在实际应用中也是不可避免的,可以考虑用第三方 openinstall 做这方面的补充。 ...

July 9, 2019 · 1 min · jiezi

angular引入富文本ngxquill自定义图片上传解决Cant-resolve-quill

1. 安装依赖npm i ngx-quillnpm i quillps:一定要安装 quill ,不然ngx-quill会报Can't resolve 'quill' in xxxx, 因为ngx-quill内部引用了quill。 2. 使用1. 引用/* 在自己的`NgModule`的`imports`里面引用,我是在`RoutesModule`里引用的 */import { QuillModule } from 'ngx-quill';@NgModule({ imports: [ ... QuillModule.forRoot() ... ]})2. 使用组件/* 直接使用 */<quill-editor></quill-editor>/* 模板绑定 */<quill-editor [(ngModel)]="content"></quill-editor>/* 响应式表单 */<quill-editor formControlName="content"></quill-editor>点击查看quill配置地址 3. css 样式引用/* 在 index.html 页面上引用 */<link href="https://cdn.quilljs.com/1.2.2/quill.snow.css" rel="stylesheet">点击查看其他css版本 3. 自定义图片上传给组件添加 onEditorCreated 方法,获取quill对象,并绑定自定义图片上传函数 html:<quill-editor (onEditorCreated)="EditorCreated($event)"></quill-editor>ts: // 富文本初始化钩子函数 EditorCreated(quill: any) { // 获取quill的工具栏对象 const toolbar = quill.getModule('toolbar'); // 给工具栏的image功能添加自定义函数,注意this指向问题 toolbar.addHandler('image', this.imageHandler.bind(this)); // 保存quill对象 this.editor = quill; } // 自定义图片上传功能 // 创建一个input对象来实现上传,除了下面的自定义代码区域,其他为官方代码 imageHandler() { const Imageinput = document.createElement('input'); Imageinput.setAttribute('type', 'file'); Imageinput.setAttribute('accept', 'image/png, image/gif, image/jpeg, image/bmp'); // 可改上传图片格式 Imageinput.classList.add('ql-image'); Imageinput.addEventListener('change', () => { const file = Imageinput.files[0]; if (Imageinput.files != null && Imageinput.files[0] != null) { /* 自定义代码 */ ....... ....... // 下面这句话必填,成功后执行 (imageUrl 为上传成功后的图片完整路径) this.editor.insertEmbed(this.editor.getSelection(true).index, 'image', imageUrl); } }); Imageinput.click(); }无注释复制粘贴版本 ...

July 9, 2019 · 1 min · jiezi

Spring-Cloud-Gateway-扩展支持多版本控制及灰度发布

灰度发布什么是灰度发布,概念请参考,我们来简单的通过下图来看下,通俗的讲: 为了保证服务升级过程的平滑过渡提高客户体验,会一部分用户 一部分用户递进更新,这样生产中会同时出现多个版本的客户端,为了保证多个版本客户端的可用需要对应的多个版本的服务端版本。灰度发布就是通过一定策略保证 多个版本客户端、服务端间能够正确对应。 所谓灰度发布,即某个服务存在多个实例时,并且实例版本间的版本并不一致,通过 实现方案nginx + lua (openresty) Netflix Zuul只需要自定义ribbon 的断言即可,核心是通过TTL 获取上下请求header中的版本号 @Slf4jpublic class MetadataCanaryRuleHandler extends ZoneAvoidanceRule { @Override public AbstractServerPredicate getPredicate() { return new AbstractServerPredicate() { @Override public boolean apply(PredicateKey predicateKey) { String targetVersion = RibbonVersionHolder.getContext(); RibbonVersionHolder.clearContext(); if (StrUtil.isBlank(targetVersion)) { log.debug("客户端未配置目标版本直接路由"); return true; } DiscoveryEnabledServer server = (DiscoveryEnabledServer) predicateKey.getServer(); final Map<String, String> metadata = server.getInstanceInfo().getMetadata(); if (StrUtil.isBlank(metadata.get(SecurityConstants.VERSION))) { log.debug("当前微服务{} 未配置版本直接路由"); return true; } if (metadata.get(SecurityConstants.VERSION).equals(targetVersion)) { return true; } else { log.debug("当前微服务{} 版本为{},目标版本{} 匹配失败", server.getInstanceInfo().getAppName() , metadata.get(SecurityConstants.VERSION), targetVersion); return false; } } }; }}维护请求中的版本号 ...

July 9, 2019 · 2 min · jiezi

iView-2019-新品发布会

我们目前正在筹划发布会的各项细节, 期待与您一起见证 iView 的成长! iView 2019 新品发布会将在 2019年07月27日14点在首都北京举办。 购票地址: https://www.huodongxing.com/event/5500465916000 线上同步直播地址: https://live.bilibili.com/1353202 活动流程13:00-13:50 签到 14:00-14:10 回顾 iView 2018 14:10-16:00 发布 iView 新产品 16:00-17:00 现场讨论、合影留念 17:00 会议结束 注:以上日程请以会议当天现场实际日程为准 参会须知由于现场至多容纳 150人,为防止无效报名,收取 35元-50元 门票,门票的所有收入将捐赠给 Vue.js 开源项目。 获取更多发布会内容,请关注 iView 官方微信公众号: 购票须知1.报名方式:点击链接,在活动行中报名 https://www.huodongxing.com/event/5500465916000 2.报名须知:凭活动行【电子票】验票签到入场 3.门票优惠:门票分为早鸟票 120 张(35元/张)和普通票 30 张(50元/张) iView 特别赞助商 iView 年度赞助商 iView 技术赞助商 iView 会议赞助商

July 9, 2019 · 1 min · jiezi

vue中的过渡动画

前言记一次vue 组件中使用 transition 和 transition-group 设置过渡动画,总结来说可分为分为 name 版, js 钩子操作类名版, js 钩子操作行内样式版... template模板结构 // 单个元素 <transition name="自定义名字"> <p v-if="show">hello</p> </transition> // 列表元素: 注意group的直接子元素是v-for渲染出来的 <ul class="list"> <transition-group name="list"> <li v-for="(item, index) in gameList" :key="item.id"> <app-horizontal :itemData="item"></app-horizontal> </li> </transition-group> </ul>name 版,name 为组件中的属性出现的过程: name-enter(初始态) => name-enter-active(中间态) => name-enter-to(终止态)消失的过程: name-leave => name-leave-active => name-leave-to以进场过渡动画为例子 我们可以分别设置 enter 阶段 和 enter-to 阶段的动画 1.设置进入时需要过渡的属性 .name-enter { opacity: 0; transform: translateY(30px) } 2.然后在 name-enter-active中设置过渡时间 .name-enter-active { transition: all .3s; } 3.最后在 name-enter-to 中写上终止态属性 其实终止态的opacity: 1;transform: none; 是默认的,可以不用写 .name-enter-to { opacity: 1; transform: translateY(0); } 如果要给列表中的元素设置交错的效果, 元素不多的话可以添加 delay 属性 .name-enter-active:nth-child(3n+1) { transition-delay: 0s; } .name-enter-active:nth-child(3n+2) { transition-delay: .1s; } .name-enter-active:nth-child(3n+3) { transition-delay: .2s; } 离场动画同理...js 钩子实现过渡动画: 通过操作类名; 就是 name 版的 js 实现// 例如实现上述列表依次显示 <ul class="list"> <transition-group v-bind:css="false" v-on:before-enter="beforeEnter" v-on:enter="enter" v-on:after-enter="afterEnter"> <li v-for="(item, index) in gameList" :key="item.id" :data-delay="index*100" > <app-horizontal :itemData="item"></app-horizontal> </li> </transition-group> </ul> // methods: { // 事先定义上述类名 // 在beforeEnter enter afterEnter 钩子中手动操作上述类名 // 初始态 beforeEnter(dom) { dom.classList.add('list-enter', 'list-enter-active'); }, // 中间态 enter(dom,done) { // 通过 setTimeout + dataset 实现过渡 let delay = dom.dataset.delay; setTimeout(function () { dom.classList.remove('list-enter'); dom.classList.add('list-enter-to'); //监听 transitionend 事件 var transitionend = window.ontransitionend ? "transitionend" : "webkitTransitionEnd"; dom.addEventListener(transitionend, function onEnd() { // 移除事件 dom.removeEventListener(transitionend, onEnd); //调用done(),表示动画已完成 done() }); }, delay) }, // 终止态 afterEnter(dom) { dom.classList.remove('list-enter-to', 'list-enter-active'); } }js 钩子过渡动画: 通过操作行内属性, 自定义动画 <ul class="list"> <transition-group v-bind:css="false" v-on:before-enter="beforeEnter" v-on:enter="enter" v-on:after-enter="afterEnter"> <li v-for="(item, index) in gameList" :key="item.id" :data-delay="index*100" data-y = "100%" > <app-horizontal :itemData="item"></app-horizontal> </li> </transition-group> </ul> // 对应的操作方法; 添加自定义的 dataset,给dom设置css样式;根据需求添加 methods: { // 初始态 beforeEnter(dom) { let { x = 0, y = 0, opacity = 0 } = dom.dataset; dom.style.cssText = `transition: .3s;opacity: ${opacity};transform: translateX(${x}) translateY(${y});`; }, // 中间态 enter(dom,done) { let delay = dom.dataset.delay; setTimeout(function () { dom.style.cssText = `transition: .3s;opacity: 1;transform: translateX(0) translateY(0);`; //监听 transitionend 事件 var transitionend = window.ontransitionend ? "transitionend" : "webkitTransitionEnd"; dom.addEventListener(transitionend, function onEnd() { dom.removeEventListener(transitionend, onEnd); done(); }); }, delay) }, // 终止态 afterEnter(dom) { dom.style.cssText = ""; } }这里记录一下监听css3的animation动画和transition事件: ...

July 9, 2019 · 2 min · jiezi

珠峰培训ES6学习笔记1

let和constvar关键字定义变量的特点: 可以重复定义不能定义常量不支持块级作用域let的特点 不可以重复定义变量不能提升,在变量定义之前,不能使用在大括号当中定义的变量(块级作用域中),在作用域外无法访问解决一些ES5当中需要闭包实现的功能,比如:每隔1秒循环输出一个当前的值const的特点 常量一旦定义,就不能被修改如果常量的值是一个引用类型,引用对象的属性还是可以修改的结构赋值ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为结构。 let arr = [1,2,3];let [a,b,c] = arr;let [,,m] = arr;// m = 3let [d,...e] = arr;// d = 1// e = [2,3]let [f,g,...h] = [1];// f = 1// g = undefined// h = []let obj = { name:"mmcai", age:28, long:165}let {name,age,long} = obj;// name = "mmcai"// age = 28// long = 165let {name:myName,age:myAge} = obj;// myName = "mmcai"// myAge = 28let {name,...O} = obj;// name = "mmcai"// O = { age:28, long:165}特点 ...

July 8, 2019 · 1 min · jiezi

微信小程序请求封装request

开始写小程序的时候对小程序请求接口的requestAPI相当无奈,因为项目急就没考虑那么多,直接开干。后边闲下来就考虑了一下做了一个封装,来统一做一些数据处理,达到减轻开发重复性,优化代码的作用: 首先我封装了一个类: import { base_url } from '../config/api' // 引入我们接口的ip,后续我们只需要传入apiconst tips = { 1: '抱歉,出现了一个错误', 1005: 'appkey无效,请求错误', 3000: '没有权限', ...} // 多种错误处理字符串----------export default class HTTP { fetch (params) { const { url, method = 'GET', data = {}, success } = params // es6对象解构请求是我们需要的传参和成功的处理 wx.request({ url: base_url + url, method, data, header: { 'Content-Type': 'application/json' }, success: res => { const { code } = res.data if (code === 0) { // 与后台约定的成功判断 success && success(res.data) // 成功的回调 return } const { error_code } = res.data this._show_error(error_code) // 失败的处理,弹出提示框 }, fail: err => { this._show_error(1) // 失败的处理,弹出提示框 } }) } _show_error (error_code = 1) { const tip = tips[error_code] wx.showToast({ title: tip ? tip : tips[1], icon: 'none', duration: 2000 }) }}这里,我们做了一个简单的基础封装,但是也是必须从回调中做出相应的处理,如果我们需要一个变量直接拿到这次请求的数据呢,那我们就需要用到promise, async await 来进行处理了,代码如下: ...

July 8, 2019 · 2 min · jiezi

你可能不知道的浏览器实时通信方案

本文主要探讨现阶段浏览器端可行的实时通信方案,以及它们的发展历史。 这里以sockjs作为切入点,这是一个流行的浏览器实时通信库,提供了'类Websocket'、一致性、跨平台的API,旨在浏览器和服务器之间创建一个低延迟、全双工、支持跨域的实时通信信道. 主要特点就是仿生Websocket,它会优先使用Websocket作为传输层,在不支持WebSocket的环境回退使用其他解决方案,例如XHR-Stream、轮询. 所以sockjs本身就是浏览器实时通信方案的编年史, 本文也是按照由新到老这样的顺序来介绍这些解决方案. 类似sockjs的解决方案还有 socket.io如果你觉得文章不错,请不要吝惜你的点赞????,鼓励笔者写出更精彩的文章 目录 WebSocketXHR-streamingEventSourceHtmlFilePollingLong polling扩展WebSocketWebSocket其实不是本文的主角,而且网上已经有很多教程,本文的目的是介绍WebSocket之外的一些回退方案,在浏览器不支持Websocket的情况下, 可以选择回退到这些方案. 在此介绍Websocket之前,先来了解一些HTTP的基础知识,毕竟WebSocket本身是借用HTTP协议实现的。 HTTP协议是基于TCP/IP之上的应用层协议,也就是说HTTP在TCP连接中进行请求和响应的,浏览器会为每个请求建立一个TCP连接,请求等待服务端响应,在服务端响应后关闭连接: 后来人们发现为每个HTTP请求都建立一个TCP连接,太浪费资源了,能不能不要着急关闭TCP连接,而是将它复用起来, 在一个TCP连接中进行多次请求。 这就有了HTTP持久连接(HTTP persistent connection, 也称为HTTP keep-alive), 它利用同一个TCP连接来发送和接收多个HTTP请求/响应。持久连接的方式可以大大减少等待时间, 双方不需要重新运行TCP握手,这对前端静态资源的加载也有很大意义: Ok, 现在回到WebSocket, 浏览器端用户程序并不支持和服务端直接建立TCP连接,但是上面我们看到每个HTTP请求都会建立TCP连接, TCP是可靠的、全双工的数据通信通道,那我们何不直接利用它来进行实时通信? 这就是Websocket的原理! 我们这里通过一张图,通俗地理解一下Websocket的原理: 通过上图可以看到,WebSocket除最初建立连接时需要借助于现有的HTTP协议,其他时候直接基于TCP完成通信。这是浏览器中最靠近套接字的API,可以实时和服务端进行全双工通信. WebSocket相比传统的浏览器的Comet)(下文介绍)技术, 有很多优势: 更强的实时性。基于TCP协议的全双工通信更高效。一方面是数据包相对较小,另一方面相比传统XHR-Streaming和轮询方式更加高效,不需要重复建立TCP连接更好的二进制支持。 Websocket定义了二进制帧,相对HTTP,可以更轻松地处理二进制内容保持连接状态。 相比HTTP无状态的协议,WebSocket只需要在建立连接时携带认证信息,后续的通信都在这个会话内进行可以支持扩展。Websocket定义了扩展,用户可以扩展协议、实现部分自定义的子协议。如部分浏览器支持压缩等它的接口也非常简单: const ws = new WebSocket('ws://localhost:8080/socket'); // 错误处理ws.onerror = (error) => { ... } // 连接关闭ws.onclose = () => { ... } // 连接建立ws.onopen = () => { // 向服务端发送消息 ws.send("ping"); }// 接收服务端发送的消息ws.onmessage = (msg) => { if(msg.data instanceof Blob) { // 处理二进制信息 processBlob(msg.data); } else { // 处理文本信息 processText(msg.data); }}本文不会深入解析Websocket的协议细节,有兴趣的读者可以看下列文章: ...

July 8, 2019 · 2 min · jiezi

什么是敏捷中的跨职能团队

什么是敏捷中的跨职能团队?跨职能 - 团队或个人会员?摘要传统上,项目是围绕组件团队(即UX,Dev,Business,Tester和......)组织的,任何需要一系列组件专业知识的版本都需要涉及多个组件团队。通常,不同的团队将有不同的优先级,这不可避免地导致产品发布周期中的瓶颈。 根据维基百科的说法,跨职能团队是一群具有不同职能专长的人,致力于实现共同目标。提高团队质量的最佳方法之一就是使其具有交叉功能。跨职能团队拥有将想法转变为工作产品的所有必要技能。 在Scrum的指南表示“在Scrum团队由的产品负责人,开发团队和Scrum Master的。Scrum团队是自组织和跨职能的。与组件团队方法相比,跨职能团队是由来自公司不同职能领域的人员组成的团队。 - 它不仅应由技术专家(后端,前端开发人员,QA工程师等)组成,还应包括业务分析师,市场营销和用户体验专家或其他积极参与项目的人员。 。 敏捷中的跨职能团队跨职能团队是帮助Scrum团队取得成功和高效工作的关键因素之一。跨职能团队具有更大的灵活性,能够更快地响应不断变化的需求,并能更好地处理持续的支持和维护。 Mike Cohn表示,“也许敏捷中最普遍和最持久的神话是,跨职能团队是每个人拥有完成工作所需的所有技能的团队。这根本不是真的......跨职能团队的成员具有各种技能,但这并不意味着每个成员都具备所有技能“ 实际上,敏捷跨职能团队不仅意味着团队本身具有跨职能性,而且每个团队成员最好也可以扮演多个角色。作为专家并不意味着会员以了解其他事情为代价而知道一件事情,理想情况下,人才形象应该是T形的,因为他/她在一个专业领域具有深度,而在其他领域具有广度。 T形专业人士跨职能团队的优势可以改善跨职能领域的协调,增加产品和流程的创新,缩短开发周期,以便从关键客户接触点获得反馈。跨职能团队消除了大多数(如果不是全部)冲突优先级问题,因为团队中的每个人都具有实现共同目标的相同优先级。 Scrum角色 什么是Scrum团队?什么是Scrum的自组织团队?Scrum团队如何运作? - 简要指南如何成为Scrum项目的优秀产品负责人?什么是产品负责人在Scrum中的角色?敏捷开发:如何成为合格的Scrum Master?什么是Scrum中的猪和鸡?项目经理与Scrum Master对项目所有者什么是三个Scrum角色?什么是Scrum Master?角色和责任什么是敏捷中的跨职能团队?作为Scrum Master,您如何帮助您的项目所有者?

July 8, 2019 · 1 min · jiezi

前端视频控件使用文档

该项视频控件是npm库中的一个控件,该控件的源地址为:https://www.npmjs.com/package... 。由于此款控件使用起来较为简单,且没有过多复杂按钮,只能实时播放摄像头画面,适合项目要求,因此选定该款控件作为视频播放控件。 总体思路:现将这款控件的代码封装为一个组件,可以方便全局实时调用。这款控件通过不同的id名称可以进行多次的调用,因此在父组件中定义不同的id名称以及视频url进行传参传入组件中。【相对原始代码有修改】 代码弊端:初始的代码需要在加载之前就提供相应的视频url,后期通过修改url无法进行重新调用,为了能通过后台请求拿到相应url,我采用了xuex数据池存值的方式,先加载请求取到相应的url,再进行组件的调用。(可以通过组件调用方式进行引用,在调用组建的时候传入url) 组件代码: 首先在控制台进行组件的安装:npm i hls.js <template> <video :id=videoValue></video> // id名称为父组件传来的videoValue的值</template><script> import Hls from 'hls.js'; // 引用Hls组件 export default { data () { return { value: this.videoValue, addre: this.add, // cameraUrl为请求后台得到的视频url数组 cameraUrl: this.$store.getters.getCameraGet.cameraGets } }, props: ['videoValue', 'add'], // 父组件传来的id名称以及下标值 mounted() { this.videoData(); }, methods: { videoData() { if (this.addre === 0) { // 通过父组件传来的下标值进行判断,找出后台传来对应的视频url var address = this.cameraUrl[0]; } else if (this.addre === 1) { address = this.cameraUrl[1] } let video = document.getElementById(this.videoValue); // 找到父组件传过来的id标签 if (Hls.isSupported()) { // 如果Hls插件支持 let hls = new Hls(); hls.loadSource(address); // 将url传入本地数据源 hls.attachMedia(video); hls.on(Hls.Events.MANIFEST_PARSED, function() { video.play(); // 播放视频 }); } else if (video.canPlayType('application/vnd.apple.mpegurl')) { video.src = address; // 不支持的时候,将url传入视频链接中 video.addEventListener('canplay', function() { video.play(); }); } } } }</script>在父组件中的代码为: ...

July 8, 2019 · 1 min · jiezi

移动端兼容问题总结1

原文地址: https://luoyangfu.com/article...input 键盘类型问题描述: 在android上只需要更换type 即可更改键盘类型,ios无效。 解决方法: 需要在表单元素外层增加<form> 标签,才能生效 文本在android 偏上问题描述: 在android上小于12px文本上下居中,android 文本显示偏上 设置字体为11px, 上下居中.解决方式1: font-size: 22px;padding: 10px 40px;border-radius: 40px;line-height: 22px;zoom: 0.5;解决方式2: font-size: 22px;padding: 10px 40px;border-radius: 40px;transform: scale(0.5);transform-origin: 0% 0%;这里都是通过先放大,然后在缩小来解决这个问题(这里应该避免使用小于12px 字体的高度) ios 输入法顶起页面问题描述:页面被输入法顶起,导致滚动,无法锁定 解决方式: 在当前容器外层再包裹一层,使用 position: fixed 来解决这个问题,做一个容器内滚动。 iconfont transform 相关操作无效描述: rotate 一个角度无效 解决方法: 需要直接操作 iconfont::before 这个伪类,不能直接对iconfont操作 .icon::before { transform: rotate(90deg);}ios 下 document.execCommand(copy) 无效在ios 下直接使用 input.select() 这种方式无效需要采用下面方式: input.setSelectionRange(0, data.length)这种方式来选取文本的长度。

July 8, 2019 · 1 min · jiezi

十分钟通关CSS内嵌样式

内嵌样式样式定义:用于辅助美化HTML,使得网页效果色彩性更高,更容易吸引用户。 样式可以为网页设置颜色、背景、排版等丰富的属性。 标签中的style属性用于帮助标签定义内嵌样式,内嵌样式格式如下例所示, 使用style作为标记,在内部写入格式如: key:value; 的数据对象来表示 具体的样式。 <div style="color: red;"> Hello World !</div>但是在标签很多的情况下,如果大量在页面中堆叠内嵌样式,则会使得页面臃肿 冗余,如下例: <div style="width: 100px; height: 100px; color: red; background-color: green; font-size: 20px; font-weight: bold; line-height: 20px; text-align: center;">大量堆积内嵌样式</div>

July 8, 2019 · 1 min · jiezi

React的移动端和PC端生态圈的使用汇总

对于一项技术,我们不能停留在五分钟状态,特别喜欢一句话,用什么方式绘制UI界面一点不重要,重要的是底层的思维,解决问题和优化的思路。由于React的生态极为庞大,本文内容部分来自一些别人的汇总,至于原文只要还是能找到的,我都会贴上地址,谢谢前期贡献的作者,如果有没有被汇总到的,欢迎在下面补充。生态圈:React官方推荐超大型项目使用的TypeScript为什么要把TypeScript放在第一位,因为TypeScript在构建超大型应用时,多人协作可以极大的加快工作效率,特别是前后端交互特别多,业务情况特别复杂的状况下(比如IM),它的优势就凸显出来了。但是在一些中小型项目中,优势并不是那么的明显。(比如做完项目跑路后期不迭代这种) TypeScript并不是一个新语言,可以简单的认为 TS= js + Type.它只是一个javascript的超集,目前更新速度也是非常快, 个人建议,在Node.js开发和React native以及大型React中使用TypeScript在下载官方的react脚手架中,包含了一个第三方的ts创建脚手架的命令 在 Create React App 中使用 TypeScriptCreate React App 内置了对 ·TypeScript` 的支持。需要创建一个使用 TypeScript 的新项目,在终端运行:npx create-react-app my-app --typescript interface IState { collapsed?: boolean, } interface IProps { props?: string | Function } constructor(props: IState) { super(props) } flag :number = 123 componentDidMount() { const result = this.FunctionTest() } FunctionTest():Promise<number|string|object>{ return Promise.resolve(false) } TypeScript写起来代码量会多一些,但是对于参数类型,返回类型,一眼明了,拥有静态类型检查,如果有问题,在编写代码时候就可以知道。补充一点,现在TS的生态已经足够适应开发,像一般的webpack插件都有了typescript的文件支持,当然,并不是所有的第三包都支持ts.在技术选型的时候就要考虑清楚这点,否则就会多做很多事情。状态统一集中管理,redux,mbox,redux-sage,dva等开源库先看看原始的react数据管理 组件间数据的传递,依靠props,状态数据提升等完成,但是对于跨层级的组件间数据传递,就不那么友好了,尤其是大型项目后期的迭代维护再说说被人吐槽,但是它的单向数据流思想不得不肯定的redux. Redux 状态及页面逻辑从 <App/>里面抽取出来, 成为独立的 store, 页面逻辑就是 reducer <TodoList/> 及<AddTodoBtn/>都是 Pure Component, 通过 connect 方法可以很方便地给它俩加一层 wrapper 从而建立起与 store 的联系: 可以通过 dispatch 向 store 注入 action, 促使 store 的状态进行变化, 同时又订阅了 store 的状态变化, 一旦状态有变, 被 connect 的组件也随之刷新使用 dispatch 往 store 发送 action 的这个过程是可以被拦截的, 自然而然地就可以在这里增加各种 Middleware, 实现各种自定义功能, eg: logging这样一来, 各个部分各司其职, 耦合度更低, 复用度更高, 扩展性更好在面试的时候,我觉得如果可以手写一个redux库,并且说清楚单向数据流的思维,是一个加分项。最终推荐使用dva,感谢前辈的开源,解放了我们 ...

July 7, 2019 · 4 min · jiezi

基于-vw-单位的移动端适配方案学习笔记

基于 vw 单位的移动端适配方案学习笔记回顾并总结一下移动端适配的一些知识前提要求"head"里添加"meta" <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />兼容性,ie9+ (ie8 让它自个儿玩去吧)计算 html 的"font-size"// 设计稿宽度, 750|640|520var designWith = 750// 设计稿上1px对应设备上多少个单位的vw, 100vw表示设备屏幕宽度var vw = 100 / designWith// html的font-size的大小// 同时也是单位rem的大小// 为了方便后面的尺寸计算,放大100倍,即设计稿上的100px;var fontSize = 100 * vw// 设置html的font-size, 可以直接写在 css 里面document.getElementsByTagName("html")[0].style.fontSize = fontSize + "vw"使用设计稿上元素的尺寸(px): eleWidth .ele { width: (eleWidth/100)rem;}code<!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>Document</title> <style> html { font-size: 13.33333333vw; /* 设计稿750px; 此时,1rem对应设计稿上的100px */ } html, body { margin: 0; } body { /* 设置默认的字体大小,这里的0.32rem=16px */ font-size: 0.32rem; } .list { list-style: none; padding-left: 0; margin: 0; } .list::after { content: ""; clear: both; } .box { float: left; width: 2.5rem; height: 2.5rem; } </style> </head> <body> <ul class="list"> <li class="box" style="background-color: #2196f3">box 01</li> <li class="box" style="background-color: #8bc34a">box 02</li> <li class="box" style="background-color: #ff5722">box 03</li> </ul> </body></html>

July 7, 2019 · 1 min · jiezi

Link-标签的预加载机制

参考文章:https://developer.mozilla.org...先简单介绍下 link 标签作用你可以在页面 <head> 元素内部使用 <link> 标签书写一些声明式的资源获取请求preload (预加载)有些资源是在页面加载完成后即刻需要的,对于这种即刻需要的资源,你可能希望在页面加载的生命周期的早期阶段就开始获取,在浏览器的主渲染机制介入前就进行预加载。 这一机制使得资源可以更早的得到加载并可用,且更不易阻塞页面的初步渲染,进而提升性能。preload 基本用例<head> <meta charset="utf-8"> <title>JS and CSS preload example</title> <link rel="preload" href="style.css" as="style"> <link rel="preload" href="main.js" as="script"> <link rel="stylesheet" href="style.css"></head><body> <script src="main.js"></script></body>preload 使用 as 指定预加载的内容的类型,将使得浏览器能够更精确地优化资源加载优先级匹配未来的加载需求,在适当的情况下,重复利用同一资源为资源应用正确的内容安全策略为资源设置正确的 Accept 请求头as 可选参数audio: 音频文件document: 一个将要被嵌入到 <frame> 或 <iframe> 内部的 HTML 文档embed: 一个将要被嵌入到 <embed> 元素内部的资源fetch: 那些将要通过 fetch 和 XHR 请求来获取的资源,比如一个 ArrayBuffer 或 JSON 文件font: 字体文件image: 图片文件object: 一个将会被嵌入到<embed>元素内的文件script: JavaScript 文件style: 样式表track: WebVTT 文件worker: 一个 JavaScript 的 web worker 或 shared workervideo: 视频文件跨域获取如果你已经有了一个可以正确工作的 CORS 设置,那么你也可以同样成功的预加载那些跨域资源,只需要你在 <link> 元素中设置好 crossorigin 属性即可 注意:如果你需要获取的是字体文件,那么即使是非跨域的情况下,也需要应用这一属性<head> <meta charset="utf-8"> <title>Web font example</title> <link rel="preload" href="fonts/cicle_fina-webfont.eot" as="font" type="application/vnd.ms-fontobject" crossorigin="anonymous"> <link rel="preload" href="fonts/cicle_fina-webfont.woff2" as="font" type="font/woff2" crossorigin="anonymous"> <link rel="preload" href="fonts/cicle_fina-webfont.woff" as="font" type="font/woff" crossorigin="anonymous"> <link rel="preload" href="fonts/cicle_fina-webfont.ttf" as="font" type="font/ttf" crossorigin="anonymous"> <link rel="preload" href="fonts/cicle_fina-webfont.svg" as="font" type="image/svg+xml" crossorigin="anonymous"> <link href="style.css" rel="stylesheet" type="text/css"></head><body> ...</body>包含媒体<link> 元素有一个很棒的特性是它们能够接受一个media属性。它们可以接受媒体类型或有效的媒体查询作为属性值,这将令你能够使用响应式的预加载!<head> <meta charset="utf-8"> <title>Responsive preload example</title> <link rel="preload" href="bg-image-narrow.png" as="image" media="(max-width: 600px)"> <link rel="preload" href="bg-image-wide.png" as="image" media="(min-width: 601px)"> <link rel="stylesheet" href="main.css"></head><body> <header> <h1>My site</h1> </header> <script> var mediaQueryList = window.matchMedia("(max-width: 600px)"); var header = document.querySelector('header'); if(mediaQueryList.matches) { header.style.backgroundImage = 'url(bg-image-narrow.png)'; } else { header.style.backgroundImage = 'url(bg-image-wide.png)'; } </script></body>上面是一个简单的例子,我们可以通过媒体查询,来根据屏幕的大小预加载不同的图片 ...

July 7, 2019 · 2 min · jiezi

video在安卓与ios实际应用中遇到的问题及解决

html5中video在安卓与ios实际应用中遇到的问题及解决安卓和IOS对于html5中的video兼容一直是大问题,各种不一样,体验还很差。这段时间做一个html的video播放的时候,要求全屏展示,真是各种问题。下面就就记一下这个项目中遇到的一下手机兼容问题和对应的处理方法。查资料的过程中,发现针对于video的兼容问题还是比较多个,会罗列视频播放的通用场景和各个场景下踩过的坑,希望在需求开发的时候,能够针对合适的场景,选择合适的技术方案。有相关的补充,欢迎大家进行补充。 1. 先了解一下 Video相关的属性src 视频的地址poster 允许用户控制视频的播放,包括音量,跨帧,暂停/恢复播放。controls 属性规定视频下载时显示的图像,或者在用户点击播放按钮前显示的图像preload 在页面加载后载入视频webkit-playsinline && playsinline 视频播放时局域播放,不脱离文档流 。但是这个属性比较特别, 需要嵌入网页的APP比如WeChat中UIwebview 的allowsInlineMediaPlayback = YES webview.allowsInlineMediaPlayback = YES,才能生效。换句话说,如果APP不设置,你页面中加了这标签也无效,这也就是为什么安卓手机WeChat 播放视频总是全屏,因为APP不支持playsinline,而ISO的WeChat却支持。x-webkit-airplay 这个属性应该是使此视频支持ios的AirPlay功能。使用AirPlay可以直接从使用iOS的设备上的不同位置播放视频、音乐还有照片文件,也就是说通过AirPlay功能可以实现影音文件的无线播放,当然前提是播放的终端设备也要支持相应的功能x5-video-player-type 启用同层H5播放器,就是在视频全屏的时候,div可以呈现在视频层上,也是WeChat安卓版特有的属性。同层播放别名也叫做沉浸式播放,播放的时候看似全屏,但是已经除去了control和微信的导航栏,只留下"X"和"<"两键。目前的同层播放器只在Android(包括微信)上生效,暂时不支持iOS。至于为什么同层播放只对安卓开放,是因为安卓不能像ISO一样局域播放,默认的全屏会使得一些界面操作被阻拦,如果是全屏H5还好,但是做直播的话,诸如弹幕那样的功能就无法实现了,所以这时候同层播放的概念就解决了这个问题。不过在测试的过程中发现,不同版本的IOS和安卓效果略有不同 安卓效果图-如图所示x5-video-orientation 声明播放器支持的方向,可选值landscape 横屏, portraint竖屏。默认值portraint。无论是直播还是全屏H5一般都是竖屏播放,但是这个属性需要x5-video-player-type开启H5模式x5­-video­-player­-fullscreen 全屏设置。它又两个属性值,ture和false,true支持全屏播放,false不支持全屏播放。其实,IOS 微信浏览器是Chrome的内核,相关的属性都支持,也是为什么X5同层播放不支持的原因。安卓微信浏览器是X5内核,一些属性标签比如playsinline就不支持,所以始终全屏。2. 常见的各种场景自动播放全屏处理播放控制隐藏视频播放的控制条video设置封面显示空白video在某些机型上,再次播放会黑屏,没图像只有声音安卓手机播放结束后,会有广告弹出... 后边问题会逐步完善 ...webview对于video原生标签的支持(存在过闪退的现象)多视频播放的时候,会存在播放黑屏??video和audio同时播放的场景,怎么兼容更好??1. 自动播放早期的安卓和IOS都需要用户手势才能自动播放,后期逐渐放宽的自动播放的策略,逐渐开始支持自动播放,当然在不同的安卓微信手机和对应的浏览器上,展示略有差异,这个没有完全清楚所以机型展示情况。 PC端的浏览器具体情况有所差别,这个没有进行深入研究,大家有采坑欢迎进行补充。 真正的做法是,检测当前的浏览器是否能支持自动播放,示例代码: var promise = document.querySelector('video').play();if (promise !== undefined) { promise.then(() => { // video can play }).catch(err => { // video cannot play })}不同的应用下,展示情况略有差异,钉钉可以支持,但是微信就禁止,但是自己提供了内置的事件来支持自动播放,示例代码:document.addEventListener('WeixinJSBridgeReady', function () { music.play()}, false)2. 全屏处理这个其实并不难,安卓和IOS,在微信环境下打开,默认应该都是全屏(不是视频占据整个手机的全屏,而是占用body内的视窗范围之内) 安卓全屏效果,没有顶部的导航栏,只有”>“ 和 ”...“,[效果如下]: ...

July 6, 2019 · 2 min · jiezi

VS-code前端配置022

VS code-前端配置 Chinese (Simplified) Language Pack for Visual Studio Code简体中文插件,一般会自动识别你的环境,自动提示是否需要简体中文的语言包。要是没有提示,就在扩展搜索一下即可。 Settings SyncSettings Sync 使用插件将目前配置保存到GitHub上,以后只需要从GitHub上获取,就可以一次性安装插件配置信息。 具体怎么配置还需要搜一下网上的配置教程,这样就不会换电脑,或者重装一下vscode 还需要重新配置。强力推荐。。。 https://juejin.im/post/5b9b5a...https://segmentfault.com/a/11...Auto Rename TagAuto Rename Tag 如题 自动重命名标签 对于前端来说还是很必要的 Auto Close TagAuto Close Tag 自动闭合标签 ES7 React/Redux/GraphQL/React-Native snippetsES7 React/Redux/GraphQL/React-Native snippets 对于用vscode 写react方便跟多 不过一些快捷键的使用需要记住熟能生巧 多用用就记住的了; 具体的快捷键 可以看插件的说明 很详细的表格: Vue 2 SnippetsVue 2 Snippets vue 提高coding 效率插件 VeturVetur vue 必备插件 ESLintESLint 语法检查。前端必备了,不过还需要根据项目配置eslintrc配置一下,否则有时候全是警告,具体为文档和配置可以看官方文档 https://eslint.org/docs/user-...JavaScript (ES6) code snippetsJavaScript (ES6) code snippets 和刚才的 ES7 React/Redux/GraphQL/React-Native snippets 比较类似,这个主要针对的是ES6; ...

July 6, 2019 · 1 min · jiezi

vue-插槽slot和-slotscope已被废弃

最近忙着写一些组件,关于插槽这一块自己还是用着 slot 和 slot-scope,然后看了一下文档的更新,于是又重新把“插槽”学习了一篇,下面一段是文档中的说明: 在 2.6.0 中,我们为具名插槽和作用域插槽引入了一个新的统一的语法 (即 v-slot 指令)。它取代了 slot 和 slot-scope 这两个目前已被废弃但未被移除且仍在文档中的特性。新语法的由来可查阅这份 RFC。插槽,也就是slot,slot就是子组件里的一个占位符,一个slot的核心问题,就是显不显示,显示的话显示话,该如何去展示出来,这是由父组件所控制的,但是插槽显示的位置是由子组件自己所决定的,slot写在组件template的什么位置,父组件传过来的模板将会显示在什么位置。 插槽的基本使用方法(匿名插槽)这是一个子组件,我们使用了默认插槽(匿名插槽),父组件的内容将会代替<slot></slot>显示出来 <template> <div> <slot></slot> </div></template><script>export default { name: 'children'}</script>// 使用children组件 <children>代替slot的内容</children>渲染后的结果 <template> <div> 代替slot的内容 </div></template>具名插槽自 2.6.0 起有所更新。已废弃的使用 slot 特性的语法在这里。有时我们一个组件里面需要多个插槽。我们怎么来区分多个slot,而且不同slot的显示位置也是有差异的.对于这样的情况,<slot> 元素有一个特殊的特性:name。这个特性可以用来定义额外的插槽: 注意:一个不带 name 的 <slot> 出口会带有隐含的名字“default”。如下面一个组件,需要多个插槽。如何向组件提供内容呢? <template> <div> <header> <slot name="header"></slot> <slot></slot> </header> <main> <slot></slot> </main> </div></template>在向具名插槽提供内容的时候,我们可以在一个 <template> 元素上使用 v-slot 指令,并以 v-slot 的参数的形式提供其名称: <!-- old --><children> <template slot="header"> <h1>Here might be a page title</h1> </template> <template slot="default"> <p>A paragraph for the main content.</p> <p>And another one.</p> </template></children><!-- new --><children> <template v-slot:header> <!-- <template #header> 具名插槽可缩写形式 --> <h1>Here might be a page title</h1> </template> <template v-slot:default> <p>A paragraph for the main content.</p> <p>And another one.</p> </template></children>渲染后的结果 ...

July 6, 2019 · 2 min · jiezi

16进制转rgba

function hexToRgba(hex, opacity) { return "rgba(" + parseInt("0x" + hex.slice(1, 3)) + "," + parseInt("0x" + hex.slice(3, 5)) + "," + parseInt("0x" + hex.slice(5, 7)) + "," + opacity + ")";}使用方法hexToRgba('#00c154', 0.2)

July 6, 2019 · 1 min · jiezi

关于Vue2一些值得推荐的文章-七月初

七月初 vue2 推荐集合查看github最新的Vue weekly;请::点击::集web前端最近很火的vue2框架资源;定时更新,欢迎 Star 一下。 七月: 不在山,不在岸,采我之时七月半。!七月-银潢七月秋浪高,黄昏欲渡未成桥。(07.01~至今): 王子乔 [唐] 宋之问 王子乔,爱神仙,七月七日上宾天。白虎摇瑟凤吹笙, 乘骑云气吸日精。吸日精,长不归,遗庙今在而人非。 空望山头草,草露湿人衣。 学习vue源码我们一起写一个Vue的Loading插件吧大白话理解和初步使用vue-routervue使用总结Vue nextTick 变迁史vuex中的四大金刚提前使用Vue 3.0新特性,vue-function-api尝鲜使用vue中的混入mixin优化表单验证插件一张图教你快速玩转vue-cli3学习vue源码—mvvmvue-router 源代码全流程分析「长文」探索Angular,React,Vue的趋势比较深入理解vue响应式原理你不知道的Vue.nextTick源码系列Vue手把手带你撸项目系列之动态面包屑为vue3学点typescript(1), 体验typescript使用 Typescript 加强 Vuex 使用体验前端规范之vue 项目规范大白话理解和初步使用vuexVue 面试知识点总结Vue 项目功能实现:刷新当前页面精读《Vue3.0 Function API》Vue入门学习之技术分享-2(深入理解Vue组件)为vue3学点typescript, 基础类型和入门高级类型vuex了解一下?Vue 面试知识点总结(二)【持续更新中~】【一文学会】vue.js入门到放弃从源码解读Vue生命周期,让面试官对你刮目相看Vue入门学习之技术分享-3(Vue中的动画特效)Vue中jsx不完全应用指南vue打包后vendor.js文件过大解决方案带你了解vue计算属性的实现原理以及vuex的实现原理记录一次vue练习的填坑记录Vue2 weekly 上Why You Should Start Front-End by Learning Vue.js Integrating content management into your Vue.js projects with PrismicVue.js Amsterdam RecordingsiView UI framework 2.4Promoted - Get all products by Creative Tim including Vue premium dashboards 90% offBest resources to learn Vue.js in 2018The Vue.js Conference in Amsterdam will have everything you hope forLaravel Nova Administration Panel with Vue.jsVuePress: What is it and Why it is a great tool to useVue.js Frameworks & Libraries to use in your next projectVueCamp: Vue.js Barcamp BerlinAmendment proposal to Function-based Component API · Issue #63 · vuejs/rfcs Why every Vue developer should be excited by Quasar 1.0 – Razvan StoenescuVue's Darkest Day – Daniel ElkingtonVue2 weekly 中What does the Vue function API feel like - Abdelrahman Awad3 Key Insights from Vue’s new functional API RFC – Kevin BallVue without View - An Introduction to Renderless Components – Jason Yu How to use cookies in VuePress - Dan VegaIn Vue, When Do I Actually Need the :key Attribute and Why? — Marina MostiWhat is VueFront? - VueFrontVue.js functional components: what, why, and when? – Austin GMigrating from Vuetify to Quasar - Stanislav Valasek10 Things You Should Know Before Writing Your Next Vuejs Component - Edithson Abelard GitHub - jamesdruhan/vue-jd-tableHow To Upgrade Your VuePress Site To v1.0 - Florimond MancaUse Fragments to Avoid Obsolete GraphQL Fields in Vue.js Applications – Markus OberlehnerReading Image Sizes and Dimensions with Vue.js – Raymond CamdenFrom JSX to Vue: my favorite templating tips – briwa A beginner-friendly guide to unit testing the Vue.js application – Vladislav BulyukhinVue2 weekly 下tiptap – a renderless rich-text editor for Vue.js VueFrontVuePress 1.x Released! – ULIVZNuxtJS: From Terminal to Browser - Sébastien ChopinTriggering events from Vue Router views - Dan VegaBuild An Intersection Observer Directive In Vue - Alex ReganBuild Decoupled Vue.js Applications with Hooks - Markus OberlehnerHow to Build a Group Chat App with Vue.js - Oscar CastroGitHub - kai-oswald/vue-svg-transitionGitHub - wokes/Laravel-Vue-SPA-template更多推荐查看github最新的Vue weekly;请::点击::集web前端最近很火的vue2框架资源;定时更新,欢迎 Star 一下。 ...

July 6, 2019 · 2 min · jiezi

EnTanMoETM项目周报62874

亲爱的ETM小伙伴: 又到了火力全开的夏天 出走半生,归来全熟 高温天气封印了身体 也阻挡了出门的步伐 只想空调房中与冰西瓜作伴 如此炎热夏季 除了与冷空气共处一室 不如与ETM作伴 看看ETM本周有何变化 以下是ETM周报具体内容 项目进展ETM-Core ETM-Core 资产发行功能,已完成 70%核心代码阶段性梳理,已完成 70%数据库结构优化,已完成 55%ETM-Module 矿机 GUI 客户端,测试中矿机 GUI 客户端跨平台研发,已完成 45%侧链数据库结构优化,已完成 50%ETM-Pay、ETM-ID 已完成 10%ETM-Mobile ETM 钱包移动端研发,已完成 30%ETM-Web WebSite 新增资讯版块日常更新,已上线Wallet v1.6 资产发行界面设计,已完成 50%社区论坛建设,测试反馈改进中运营进展社群数据 官方微信社群数量:210+,活跃率 65%官方微信社群人数:57600+官方微信客服好友:14000+官方电报群人数:52000+官方微博关注人数:11100+官方微信公众号关注人数:1900+官方微信社群奇点群增加到 20个运营数据 官方微信公众号发布 3 篇图文官方微博发布 18 条微博,阅读总量 2万+在金色财经、币世界、陀螺财经、币乎、CSDN、简书、大鱼号、百家号、头条号、知乎号、企鹅号等各内容平台发布文章社群活动 “日拱一卒”:本周知识点为多重签名、环签名、分布式存储、P2P存储等7个名词,后台回复“日拱一卒”查看本周合辑,点击菜单栏“日拱一卒”获取两个月合辑。“圆桌派”话题讨论:# 比特币冲破万元大关,上车还是下车?#“争分夺秒”:每周二 16:00 社群抢答活动,本期 5 题,每题奖励 5 ETM“Momo答题”:微博每日抢答送出 1 ETM币“社区红人榜”:月末评选 5 位社区红人,发放丰厚奖励

July 5, 2019 · 1 min · jiezi

移动端的3种适配方法

做移动端页面以来,经常会听说移动端的适配这个问题,但是并没有认真分析过是如何适配各种机型的。目前公司用的是手淘的flexible.js进行页面适配的。适配的根本原理其实就是将设计稿按一定的比例在不同的手机上实现。 在分析移动段适配之前首先要了解一下rem, css3的一个相对长度单位。既然是相对长度,那就有一个参照体了,rem就是相对于html元素的font-size计算值的倍数。即1rem 等于一倍的html元素的font-size值。 接下来分析一下三种移动端适配的方法一、@media + rem最早看到这个适配是在同事的代码里,当时并不知到是什么原理,也并不明白这些数字是怎么来的。@media screen and (min-width:350px){ html{font-size:342%;}}@media screen and (min-width:360px){ html{font-size:351.56%;}}@media screen and (min-width:375px){ html{font-size:366.2%;}}@media screen and (min-width:384px){ html{font-size:375%;}}@media screen and (min-width:390px){ html{font-size:380.85%;}}@media screen and (min-width:393px){ /* 小米NOTE */ html{font-size:383.79%;}}@media screen and (min-width:410px){ html{font-size:400%;}}@media screen and (min-width:432px){ /* 魅族3 */ html{font-size:421.875%;}}@media screen and (min-width:480px){ html{font-size:469%;}}@media screen and (min-width:540px){ html{font-size:527.34%;}}@media screen and (min-width:640px){ html{font-size: 625%;}}@media screen and (width:720px){ html{font-size: 703.125%;}}@media媒体查询, 可以针对不同的屏幕尺寸设置不同的样式,特别是如果你需要设置设计响应式的页面,@media 是非常有用的。当你重置浏览器大小的过程中,页面也会根据浏览器的宽度和高度重新渲染页面。上述代码中,第一个@media screen and (min-width:350px)表示当移动设备的宽度大于350px的时候页面将使用花括号内的样式,即将html根元素的字号设置为342%。(max-width:350px,则表示设备宽度小于350px时将采用此样式)。上述css代码的作用可见就是在不同分辨率的设备上设置不同的html字体大小。 ...

July 5, 2019 · 2 min · jiezi

开发一个基于-Vue20-的个人天气预报

本场 Chat 是一个基于 Vue 的个人天气预报项目,就是兴趣所致,做来玩玩。顺便扩展一下知识面。 本项目会采用高德地图 API,Echarts 可视化库和 Vue 相关的技术来开发本项目。有兴趣的同学,可以一起来玩玩。 本场 Chat 你将学到如下内容: 学会制作自己的天气预报;学会使用部分高德地图的 API;学会使用 Echarts的部分 API;Vue+Webpack 相关的一些技术。有兴趣的请到gitchat查看: https://gitbook.cn/gitchat/ac... 效果图如下:

July 5, 2019 · 1 min · jiezi

VueBetterScroll-实现多Tab上拉加载更多实例

本场 Chat 是讲一个基于 Vue+Better-Scroll 实现多 Tab 切换上拉加载更多的实例,像这种多 Tab 切换加载更多的场景,不管在 PC 端还是移动端都还挺常见的,比如商城类,订单中心等。本人在项目中也经常用这种,已经轻车熟路了,所以就想做个总结出来,并做成一个实例 Demo,把经验分享出来,供同样有所需的前端同学学习。 本项目使用 Vue 和 Better-Scroll 相关的技术来开发本项目。通过学习本项目,你也可以做出多 Tab 切换上拉加载更多的效果,而不必到处找别人的例子。 本场 Chat 你将学到如下内容: 学到 Better-Scroll的相关知识;学到 Vue 开发的相关知识;学到用 Vue+Better-Scroll实现多 Tab 切换上拉加载更多。有兴趣学习的可以请到gitchat查看: https://gitbook.cn/gitchat/ac... 效果图如下:

July 5, 2019 · 1 min · jiezi

CSSCSS3-实现-居中水平垂直

1,水平居中:行内元素 把行内元素放在一个属性块(display:block)元素中,然后设置父层元素属性居中: .test { text-align:center;} 2,水平居中:块状元素 设置外边距 .test { margin: 100px auto;} 3,水平居中:多个块状元素 把块状元素属性(display:inline-block),然后设置父层元素属性居中: .test { text-align:center;} 4,水平居中:多个块状元素(flexbox布局实现) 把块状元素的父元素属性 display:flex和justify-content:center,如下设置: .test { text-align:center;} 5,垂直居中:单行的行内元素 设置height和line-height属性 .test { height: 100px;line-height:100px; } 6,垂直居中:多行的行内元素 给要居中的父元素设置display:table-cell和vertical-align:middle属性 .test { background: red;width: 200px;height: 200px;/* 以下属性垂直居中 */display: table-cell;vertical-align:middle;} 7,垂直居中:已知高度的块状元素 给要居中的元素设置如下属性 .test { top: 50%;margin-top: -50px; /* margin-top值为自身高度的一半 */position: absolute;padding:0;} 8,水平垂直居中:已知高度和宽度的元素 给要居中的元素设置如下属性 (1).test { position: absolute;margin:auto;left:0;top:0;right:0;bottom:0;}(2) .test{ position: absolute;top: 50%;left: 50%;margin-top: -75px; /* 设置margin-left / margin-top 为自身高度的一半 */margin-left: -75px;} 9,水平垂直居中:未知高度和宽度元素 给要居中的元素设置如下属性 .test { ...

July 4, 2019 · 1 min · jiezi

jQuery源码解析系列一目录

起初选择先看jQuery源码而不是react的原因也简单:jQuery作为每个前端会用的第一个框架,虽然过时,但却又如此普及,所以想看看它是咋设计的。 从 2019.3.22 到 2019.07.01,前前后后写了 27 篇文章,但由于jQuery作为大而全的框架,一来 全部看掉太费时间和精力(你可以从下面的目录看到,Sizzle引擎、Deferred还没有看),二来 时间拖得挺久的了,有些厌倦。 所以jQuery的源码解析系列,暂且告一段落了,27 篇文章目录如下: jQurey-3.3.1源码解析(天啦噜,它出3.4.1了) 节点遍历 jQuery的遍历结构设计之遍历祖先 jQuery之documentFragment 当我调用了$().append()后,jQuery内部发生了什么? jQuery内部对<script>标签的处理 jQuery的遍历结构设计之遍历同胞 文档处理 jQuery之html()的实现 jQuery之text()的实现 jQuery源码解析之after()/insertAfter()/before()/prepend()的实现 jQuery源码解析之replaceWith()/unwrap() jQuery源码解析之detach()/empty()/remove()/unwrap() jQuery之getAll()和cleanData() jQuery源码解析之clone() 元素操作 jQuery源码解析之offset() jQuery源码解析之position() 样式操作 jQuery源码解析之width() jQuery源码解析之addClass(),removeClass(),toggleClass()和hasClass() 事件体系 jQuery源码解析之click()的事件绑定 jQuery源码解析之trigger() addEvent.js源码解析 jQuery源码解析之你并不真的懂事件委托及target和currenttarget的区别 jQuery源码解析之jQuery.event.dispatch() jQuery之事件绑定到触发全过程及知识点补充 模拟实现jQuery的$().on()和$().trigger() 动画引擎 jQuery源码解析之$.queue()、$.dequeue()和jQuery.Callbacks() jQuery源码解析之$().animate()(上) jQuery源码解析之$().animate()(下) jQuery之模拟实现$().animate()(上) jQuery之模拟实现$().animate()(下) github:https://github.com/AttackXiaoJinJin/jQueryExplain 希望对你有些帮助! (完)

July 4, 2019 · 1 min · jiezi

h5-vue引入微信sdk-实现分享朋友圈分享给朋友获取地理位置

最近入职的公司主要做微信端的h5,所以在所难免要引用sdk。虽然官方文档写的还算清楚,但是还是有坑。 1.在index.html中 引入微信sdk<script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.4.0.js"></script>2.在assets/js 下新建文件 wx.jsexport default { wxShowMenu: function (that,sign='') { let url = window.location.href.split('#')[0] that.$http.post('/xxx', //请求你们公司后台的接口 获取相关的配置 that.$getSingQuery({ appKey: 'xxx', url })) .then(res => { var getMsg = res.data.data; // console.log('微信配置----------') // console.log(res.data) wx.config({ debug: false, //生产环境需要关闭debug模式 测试环境下可以设置为true 可以在开发者工具中查看问题 appId: getMsg.appid, //appId通过微信服务号后台查看 timestamp: getMsg.timestamp, //生成签名的时间戳 nonceStr: getMsg.noncestr, //生成签名的随机字符串 signature: getMsg.sign, //签名 jsApiList: [ //需要调用的JS接口列表 'updateAppMessageShareData', //自定义“分享给朋友”及“分享到QQ”按钮的分享内容(1.4.0) 新接口 'updateTimelineShareData', //自定义“分享到朋友圈”及“分享到QQ空间”按钮的分享内容(1.4.0) 老接口 'onMenuShareTimeline', //分享到朋友圈 老接口 'onMenuShareAppMessage',//分享给盆友 老接口 'getLocation' //获取定位 ] }); wx.error(function (res) { // alert(JSON.stringify(res)) console.log(res) // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。 }); wx.ready(function () { if(sign=='location'){ //由于 获取定位往往是页面一加载 就提示获取地理位置 所以可以直接在写在 wx.ready wx.getLocation({ type: 'wgs84', // 默认为wgs84的gps坐标,如果要返回直接给openLocation用的火星坐标,可传入'gcj02' success: function (res) { var latitude = res.latitude; // 纬度,浮点数,范围为90 ~ -90 var longitude = res.longitude; // 经度,浮点数,范围为180 ~ -180。 var speed = res.speed; // 速度,以米/每秒计 var accuracy = res.accuracy; // 位置精度 that.latitude=res.latitude; that.longitude=res.longitude; that.geocodeRegeo()//逆地理编码 调用你vue实例里的方法 do something... } }); } }); }) .catch(error => { alert(error) console.log(error) }) }}3.在main.js 将WXConfig绑在vue原型上 这样哪个页面需要初始化 直接通过原型就可以拿到import WXConfig from './assets/js/wx' //微信分享Vue.prototype.WXConfig = WXConfig4.在需要的页面 进行初始化微信JS-SDK说明文档:同一个url仅需调用一次,对于变化url的SPA的web app可在每次url变化时进行调用。 ...

July 4, 2019 · 2 min · jiezi

LoaderX-图片加载插件

非常简单的图片加载插件,封装了常用方法。仓库地址: https://github.com/wenyiweb/l...喜欢可以给一个star哦,可以提需求~有问题可以加群一起讨论,qq群:692337464 Install baseyour html <script src="loaderx.min.js"></script>npmnpm i loaderxyour app.jsimport LoaderX from 'loaderx'方法介绍 add() 添加图片资源 addProgressListener() 监听加载进度 addCompletionListener() 监听完成事件 start() 启动 具体使用方法可参考example目录的示例。

July 4, 2019 · 1 min · jiezi

前端报错检查指南

JavaScript报错即代码报错语法报错 比如语法错误 - 逻辑报错 逻辑错误,是说你脑袋中预想与现实结果不符,这时重新思考自己的逻辑。

July 3, 2019 · 1 min · jiezi

移动端实现列表左滑删除react

最近做了一个类似系统操作的左滑删除的demo,用的taro框架,和大家分享一下~首先需要考虑的有以下几点:1)布局;2)判断是左滑还是右滑,左滑时出现删除,右滑时回归原位;3)排他性,意思是某一个时间只能有一个项出现删除,当有另一个出现删除时,上一个自动回归原位。我将列表项封装成一个组件,而整个列表是另一个组件。接下来先说列表项这个组件,逐一解决以上这些问题:1)布局我采用的是列表项最外层套一个盒子,这个盒子宽度设置为100vw,并且overflow:hidden。而列表项要包括内容和删除按钮,内容宽度为屏幕宽度,而删除按钮定位到右边,所以整个列表项宽度是超过100vw的。描述可能没有那么清晰,直接上代码: <View className='swipe-item'> <View className='swipe-item-wrap' style={moveStyle}> <View className='swipe-item-left' onTouchStart={this.handleTouchStart} onTouchMove={this.handleTouchMove.bind(this, index)} onTouchEnd={this.handleTouchEnd} > <View>{item.title}</View> </View> <View className='swipe-item-right'> <View className='swipe-item-del'>del</View> </View> </View></View>.swipe-item { width: 100vw; overflow: hidden; line-height: 24PX; height: 24PX; text-align: center; margin-bottom: 10PX; &-wrap { width: calc(100vw + 32PX); height: 100%; position: relative; } &-left { width: 100vw; } &-right { width: 32PX; height: 100%; background: pink; position: absolute; right: 0; top: 0; }}好了,布局结束之后,接下来是第二个问题:2)判断是左滑还是右滑,左滑时出现删除,右滑时回归原位可以看到上面的代码,我已经在列表项左边部分加了touch的一系列事件,下面就来分析下这几个事件 touchstart:开始时,要获取当前位置touchmove:滑动时,获取滑动时的位置,同时纵向滑动时阻止。来判断当前是左滑还是右滑,左滑时e.touches[0].pageX在减小,而右滑时变大。为了防止一个手误操作,我加了一个判断,当滑动超过一定距离时才动。并且记录下当前滑动的是第几项。在render的时候给列表项加一个样式就可以实现了,就是第一段代码中的style。touchend:滑动结束上代码了~ handleTouchStart = e => { this.startX = e.touches[0].pageX this.startY = e.touches[0].pageY } handleTouchMove (index, e) { // 若想阻止冒泡且最外层盒子为scrollView,不可用e.stopPropogagation(),否则页面卡死 this.currentX = e.touches[0].pageX this.moveX = this.currentX - this.startX this.moveY = e.touches[0].pageY - this.startY // 纵向移动时return if (Math.abs(this.moveY) > Math.abs(this.moveX)) { return } // 滑动超过一定距离时,才触发 if (Math.abs(this.moveX) < 10 ) { return } else { // 否则没有动画效果 this.setState({ hasTransition: true }) } // 通知父组件当前滑动的为第几项 this.props.onSetCurIndex(index) } handleTouchEnd = e => { // 结束时,置为true,否则render时不生效 this.setState({ hasTransition: true }) }3)排他性这个主要是通过触发父组件的一个事件,在父组件中设置一个当前滑动项的index值,然后再通过props值传入子组件,渲染的时候加一个判断实现。 ...

July 3, 2019 · 1 min · jiezi

如何优雅的使用wxParse组件形式

基于wxParse的二次封装,以组件的方式使用 先看效果   使用方法: 1、复制HtmlView文件夹到你的项目component中, 2、引用页面json中加入组件对应路径 3、由于没有可用api,所以我这里用写死的,请求来的一样可用 4、页面中加入  <HtmlView detail="{{你的数据名称}}"/> 大功告成! github地址:https://github.com/nomore3324...

July 3, 2019 · 1 min · jiezi

对前后端通信的基本了解如何通信跨域

1、什么是浏览器的同源政策限制?端口,域名,协议 ,只要一个不一样就跨域2、前后端如何通信?常见通信的几种方式 Ajax : 短连接Websocket : 长连接,双向的。CORS fetch()Form表单(最原始的)Ajax是如何通信的 基本通信原理:浏览器可以发出HTTP请求与接收HTTP响应,实现在页面不刷新的情况下和服务端进行数据交互。实现过程:1) 创建XMLHttpRequest对象(异步调用对象)var xhr = new XMLHttpRequest();2) 创建新的Http请求(方法、URL、是否异步)xhr.open(‘get’,’example.php’,false);3) 设置响应HTTP请求状态变化的函数。onreadystatechange事件中readyState属性等于4。响应的HTTP状态为status==200(OK)或者304(Not Modified)。4) 发送http请求xhr.send(data);5) 获取异步调用返回的数据优点:提高用户体验,较少网络数据的传输量Fome表单是如何通信 基本通信原理:通过form表单以post/get方式提交数据。实现过程:当你点击submit按钮时,浏览器会默认把你在input里面输入的数据,以post或get的方式提交到form表单中的action这个地址。相当于你提交表单时,就会向服务器发送一个请求,然后服务器会接受并处理提交过来的form表单,最后返回一个新的网页。缺点:1、单项提交,页面会发生跳转或刷新,导致用户体验不好3、浪费宽带。改用ajax。了解Websocket 建立在TCP协议之上,与HTTP协议有着良好的兼容性3、跨域通信有几种?引JSONPHash(url#后面的,改变页面不刷新)postMessage(H5中新增的)WebSocketCORS介绍以下最常用的JSONP 1.JSONP原理利用<script元素的这个开放策略,网页可以得到从其他来源动态产生的 JSON 数据。JSONP请求一定需要对方的服务器做支持才可以。2.JSONP和AJAX对比JSONP和AJAX相同,都是客户端向服务器端发送请求,从服务器端获取数据的方式。但AJAX属于同源策略,JSONP属于非同源策略(跨域请求)3.JSONP优缺点JSONP优点是兼容性好,可用于解决主流浏览器的跨域数据访问的问题。缺点是仅支持get方法具有局限性4、GET与post区别?POST与GET的区别1、GET请求会被浏览器主动缓存,而POST不会2、GET请求参数会被完整保留在浏览器历史记录里,而POST中参数不会被保留3、GET请求在URL中传送的参数是有长度限制的,而POST没有限制4、GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息本质上都建立在TCP链接上

July 3, 2019 · 1 min · jiezi

html5设计原则2007

原文:https://www.w3.org/TR/html-de... 摘要HTML5是万维网核心语言HTML的第五个主要版本,本文档描述了HTML发展工作组使用的一套指导原则。在设计HTML时,这些原则提供了在兼容性、实用性、可交互性领域的指导 1.简介HTML工作组有来自很多不同社区包括WHATWG和其他W3C工作组的代表。在whatwg下的HTML5工作,以及过去几年中在各种W3C标准上的大部分工作,都是基于不同的目标和对优秀设计的不同想法。为了取得有用的进展,我们需要就这个小组的目标达成一些基本共识 1.1.文档和实现的一致性很多语言规范会对有效文档定义一套一致性要求,与相应的处理有效文档的实现一致性要求。而HTML5在对非标准文档的实现一致性上有一些不同寻常规范的双重性使我们能够为作者提供一种相对清晰和可理解的语言。同时也支持现存的文档使用旧的或者非标准的结构,也允许交互性更好的错误处理一些设计原则更多应用于内容的一致性要求(conforming language,一致性语言),另外一些更多应用于实现的一致性要求(supported language,支持语言),支持语言是一致性语言的严格超集,会有想当多的重叠 2.兼容性有很多方法可以解释兼容性,有时会用到‘向前兼容’、‘向后兼容’等术语,但往往这些术语的含义是不清晰的。本节的原则讨论了兼容性的不同方面。 2.1支持现存内容这条原则主要应用与支持语言现存内容常常依赖期望的用户代理(user agent)和行为来达到预期。实施规范必须确保可以处理绝大多数现存内容。特别是它应该可以把现存的HTML当做HTML5处理并且达到作者和用户的预期而无需模式切换 内容依赖浏览器的可能有多种形式。它可能依赖早期的HTML规范的元素、属性或者API,或者一些专属特性。它可能依赖特定的错误处理规则。在较少情况,可能依赖早期的HTML规范中的非标准实现特性 当考虑对遗留特性或表现的改变,对当前实现和作者期望,下面的问题需要纳入考虑 是否有相当多数量的内容依赖于这个特性或者表现某个依赖的内容是否发生于特别流行的网站依赖性内容是否真正用于消费,而不是仅出现在测试用例或示例中?依赖性内容是出现在公网还是仅仅供有限用户访问的内部网络依赖性内容意图作用与多个流行的UA,或者仅仅指向某一种UA,或者非常旧的或者不流行的UA建议更改的益处和破坏内容的代价应该根据这些标准进行权衡。在某些情况,如果某个非标准特性或表现满足有效用户场景,把它加入一致性语言是可取的 2.1.1.例子 许多网站使用损坏的标记,例如嵌套不良的元素 (abc),作者和用户都寄希望于UA的错误处理。对这种内容的处理我们需要定义与预期兼容的处理要求一些网站使用<u>元素来展示下划线效果2.2优雅降级这条原则主要用于一致性语言网站作者通常不情愿使用新语言特性,因为可能会在旧的UA上引发问题的新,或者没有提供优雅回退方法。HTML5文档一致性要求应设计为在旧的或者缺乏能力的UA上可以优雅降级,即使使用了新的元素、属性、API和内容模型考虑所有UA包括一些非常旧的浏览器版本或者极不流行的工具是不可取的。当然下面一些类型的UA需要着重考虑 最主流浏览器的当前版本主流浏览器旧的但是流行的版本设计用于满足特定需求或者解决特定市场的顶级UA,如辅助技术、移动浏览器,或者非典型媒体如纯文本终端或打印的UA在某些场景,一个新特性可能不适用于特定类型的UA,或者可能无法以一种可以降低质量的方式进行设计。例如新的脚本API不能在无脚本UA上运行。但很多场景可以使用下面的方法 一个新的元素或属性可以提供额外的语义,如此在不被理解时也不会失去基本功能一个新的脚本方法或者属性在使用前可以先使用ECMAScript内省工具做测试一个新的元素或属性可能会提供语义和一个简单的使用css实现的默认呈现,这样附加的小样式表就可以优雅降级一个新元素,属性或脚本API的表现可能通过附加的脚本来模拟实现,尽管脚本方法可能在性能和易用性水平上不相同一个新的元素可能需要高度专业化的呈现,但允许给不理解的UA提供不同的内容作为回退这个列表并不详尽;在某些情况下,稍微复杂一些的方法更有效 2.2.1. 例子 irrelevant属性的默认展现可以通过css规则[irrelevant] { display: none; }来模拟实现多媒体元素如<canvas> fallback </canvas> 或 <video> fallback </video>在旧的UA上会显示回退内容getElementsByClassName()方法在UA不支持时可以基于脚本实现<datalist>元素可能包含一个隐藏的<select>元素并且与 <input>元素关联。这种组合框的回退可以使用一个文本框或者一个文本框关联一个弹出式菜单来实现2.3.不要重新发明轮子如果已经存在广泛使用和实施的技术能够覆盖特定用例,就要考虑指认这个技术而不是为同样的意图发明一个新东西。但也有时候,新的用例要求一个新的方式而不是在旧方法上进行拓展 contenteditable="" 在UA上早已使用和实施,没必要去发明一个新特性2.4.铺好牛道当某种实践在作者中已经广泛流传了,接受它比禁止它或者发明新东西更可取 作者们在HTML中已经使用了<br/>语法而不是 < br>,允许这样做没有任何害处2.5.进化而不是革命革命有时会使世界变好。然而通常来说演化一个设计比抛弃它更好。这样作者不必学习新的模型内容也会寿命更长。更确切的说,这意味着设计者设计的特性能够使旧内容享受它的优点而不必做不相干的改变。实施应该能够在现有代码上增加新特性,而不用开发整个独立的模式 切换到xml语法需要全球变更,因此继续支持经典的HTML语法3.公共设施这些原则要求一个能恩确保HTML有效地实现预期目的设计 3.1.解决现实问题对规范的更改应该解决现实世界的问题。非基于现有需求的抽象结构设计比不上解决具体问题的实用设计。如有可能,应解决普遍存在的问题 3.2.选区的优先权在有冲突的情况下,用户利益高于作者高于实施者高于专业人士高于纯理论。换个方式说在权重上,应用户成本和难度>实施者成本>规范作者成本>仅出于理论的提案。 3.3.设计安全确保特性不破坏web安全模型,最好直接在规范中解决安全问题 不同站点的跨文档沟通很有用,但是不严格的版本可能把用户数据至于险境。跨文档消息只有在不违反安全约束的条件下才允许3.4.关注点分离HTML应该允许内容和表现分离。基于这个理由,表示结构的标记通常优先于纯展示标记。而且,结构性标记是一种结束的手段,如果无法结束则需要进行深入详细和语义编码。为不同媒体定义合理的默认展示就足够了。HTML在语义表达和实用性之间取得了平衡。标记中的元素和属性的名称可能是简写的而不是精确完整的 article元素定义一个单独的文章,而不是它怎样展示的细节。一个杂志文章可能是页面上唯一的文章,多列格式,而博客站点上则可能一个页面上有多个文章,显现为有边框的盒子3.5.DOM一致性序列化解析器构造的DOM树对脚本和其他能在文档树上操作的程序代码的可行性要保持一致,允许实现的兼容性差异,但应尽可能小 HTML (text/html)解析器把http://www.w3.org/1999/xhtml...4.交互性这些原则用来提升HTML可交互性 4.1.明确的行为最好清晰定义内容作者可以依赖的行为,而不是模糊的或实现定义的行为。这样更容易编写各种UA中的内容。当然实施依然可以自由地对用户界面和渲染质量做出提高 4.2.避免不必要的复杂性简单的解决方案比复杂的更受欢迎,简单的特性也更容易实现,可操作性更高,也更便于作者理解。不过这不能成为违反其他原则的接口 4.3.错误处理优雅的错误恢复比硬故障更好,这样编写错误就不会暴露给用户 5.通用接入特性的设计必须可通用接入。这个类别覆盖各种相关的原则 5.1媒体独立设计的特性必须可跨平台、设备、媒体工作。这并不是说如果某个媒体或平台不支持就省去这个特性。例如一些交互特性不会因为无法在打印文档上表现出来就有去掉它们。 HTML的重排能力使其更适合可变屏幕尺寸,而不是精确字形位置的表示超链接在打印文档上并不会有动作,但我们没有理由要去掉a元素 5.2.支持世界语言可使用世界上所有的语言发表。但并不是说要把它当做一个均衡语言系统禁止不支持所有语言的特性。把多个翻译打包到一个文件里的特性超出了这个范畴 支持Unicode允许世界上大多数语言,包括不同语言的混合文本意大利文很有用,因为它适用于很多二进制的脚本,尽管很多脚本并没有这种概念。类似的,ruby对很多脚本有用,尽管它有一个CJK焦点 元素内容中的文本相比属性内容中的文本有更好的语言支持;元素内容中可插入ruby注释,以及dir属性和bdo元素,以防Unicode双向算法不能正确的对相邻的混合方向文本排序 5.3.可用性特性的设计必须对有残障的用户可用。对所有人可用很重要。但也不是说如果特性不是对所有人可用就完成省去它,而是提供替代机制 图像元素对盲人不可见,因此可以提供一个替代文本progress元素本质是可以访问的,因为它具有明确的进度条语义,允许映射到可访问api

July 3, 2019 · 1 min · jiezi

前端面试汇总htmlcss

HTML: 1、前端页面有哪三层组成?分别是什么?有什么作用? 前端页面由结构层HTML,表示层CSS,行为层JS组成。2、HTML5为什么只用写<!DOCTYPE html>? HTML5不是基于SGML,因此不需要对DTD进行引用,但是需要doctype来规范浏览器的行为(让浏览器按照它们应该的方式来运行);而HTML4.0基于SGML,所以需要对DTD进行引用,才能告知浏览器文档所使用的文档类型。3、Doctype作用?标准模式与兼容模式有什么区别? !DOCTYPE声明位于HTML文档的第一行,处于HTML标签之前,告知浏览器的解析器用什么文档标准解析这个文档,DOCTYPE不存在或者格式不正确会导致文档以兼容模式存在。4、HTML5有哪些新特性?移除了哪些元素?如何处理HTML5新标签的浏览器兼容问题?如何区分HTML和HTML5? 1)新特性: HTML5现在已经不是SGML的子集,主要是关于图像、位置、存储、多任务等功能的增加; 绘画canvas; 用于媒介回放的video和audio元素; 本地离线存储localstorage长期存储数据,浏览器窗口关闭数据不丢失; sessionStorage的数据在浏览器窗口关闭后自动删除; 语义化标签,footer、header、nav、section等; 表单控件data、email、time、url、search等; 新增了地理定位功能,getCurrentPosition();2)移除的元素: big、center、font、s等;3)支持HTML5新标签: IE8/IE7/IE6支持通过document.createElement方法创建的标签,可以利用这一特性让浏览器支持性标签。4)区分HTML和HTML5: HTML5会声明DOCTYPE; 标签的使用; h5新增的功能使用;CSS

July 3, 2019 · 1 min · jiezi

candystool-low-code的一种尝试

刚开始接触Low code/0 code这种概念的时候,是源于我们项目组的一个简单的需求。这个需求就是怎样动态化去做一个表单,以及表单查询页面。 思考阶段于是开始了简单的思考,对于通常中后端的管理平台,前端要处理的业务逻辑大概分为查询数据进行列表展示,详情页面展示,内容字段编辑等方面。就拿列表展示页面来说,我们可以把查询条件抽象出来,通过一个数组去配置,表单的元素也通过选择类型配置出来(如Input,select,dataPicker等),然后定义其特有的属性值。查询所调用的接口也暴露出配置项,然后查询返回的结果,通过一个arr去存储字段的key值。由此类推,详情展示页面和内容编辑页也暴露出api层和字段层去配置。 准备及开发阶段接下来我们需要结合一个UI组件库,或者有时间的话,手写一个组件库也可以,自己手写的话,可改性会更高一些。目前我们项目里采用的UI组件都是自己手写的。然后是几种模板的开发,目前模板包括 :查询列表页模板 、新增页模板、编辑页模板、详情页模板 四种模板。开发完模板,接下来就是交互方式了,比如我要在一个查询结果,点击配置编辑按钮,优雅的在当前页面去加载配置的编辑页面,而不是跳转到另外一个页面去做(这样比较low),其实我们的做法是做一层路由模板,路由模板控制着数据的流动。在列表页模板里设置按钮的交互方式,路由模板根据这个交互方式,去打开一个modal,里边引入跳转目标页模板。 进阶阶段有了这个初步的模板工具后,我们还是觉得不太满足。因而我们要求有一个diy布局模板,每个diy里的模块,可以引入其他的模板,有时候会感觉这样有点太乱,模板之间的通讯还没想好,我们也在不断的尝试,希望有小伙伴可以一起加入 接下来要做的事:扩大模板库配置文件的本地化,目前配置文件是在数据库存的,在本地化会更快一些。模板间的通讯未完思考中。。。我们做出来的成果

July 3, 2019 · 1 min · jiezi

CSS零碎之emrem

移动端的开发基本很少直接使用px作为单位了,目前最常用的是rem。不过在这之前其实还有个em单位,和rem长得非常的像,那么它们有什么区别呢?又有什么不一样的适用场景呢? 注意:无论使用em,还是rem,客户端最终解析的值依旧是px!em:相对父级元素字体大小的倍数从title的解释就可以看出,em的基准是其父级元素,不过这个父级元素要求是设置有font-size值的,如下面的例子: <div class="father" style="font-size:20px;"> <div class="son" style="font-size:2em;"></div></div>那么son的字体大小就是2 * 20px = 40px,此时,如果father的字体大小变化了,那么son的也会跟着变化。假如没有父元素,则基准就是body(由于默认浏览器默认字体为16px,所以默认情况1em=16px)。 rem:相对 html 根元素字体大小的倍数跟上面解释body基准时的差不多,默认情况下1rem=16px。此时,只要根元素字体大小不变,那么相对于它的rem就不会变。对于移动端的各种机型来讲,由于不同的机型屏幕尺寸、分辨率都不一样,不太可能使用相同的根元素字体大小作为基准,所以所谓rem布局,就是通过js动态计算出不同机型的根元素字体大小值,来对页面进行等比例的缩放,达到适配大部分机型的效果。那么具体如何去设定这个基准呢?假设把手机屏幕宽度均分成10等份(因为rem布局就是针对宽度去做设定的),规定其中的一份作为根元素的font-size值,那么根元素font-size值就可由下述公式获得: document.documentElement.style.fontSize = document.documentElement.clientWidth / 10 + 'px';在这个基准下,那么1rem的值也随之得到了: 1rem = document.documentElementstyle..fontSize = document.documentElement.clientWidth / 10 + 'px';那么,不同屏幕的机型由于屏幕宽度不同,也就得到了在"屏幕宽度均分成10等份"这个标准下的rem相对值。比较完整的计算方式如下: // set 1rem = viewWidth / 10function setRemUnit () { var rem = docEl.clientWidth / 10 docEl.style.fontSize = rem + 'px'}setRemUnit()// reset rem unit on page resizewindow.addEventListener('resize', setRemUnit)window.addEventListener('pageshow', function (e) { if (e.persisted) { setRemUnit() }})注意:这里的标准 "10"可以是任一值,只要跟下面转换公式中用到的标准值保持一致即可,这里只是为了计算方便才这么设定。这样,rem的基础生态就搭建好了。那么如何基于这套标准应用到开发中去呢? 在继续之前,先来了解下"像素"这个知识点,因为接下来都会用到它的概念。 像素分为两种:设备像素和CSS像素 1、设备像素(device independent pixels): 设备屏幕的物理像素,任何设备的物理像素的数量都是固定的 2、CSS像素(CSS pixels): 又称为逻辑像素,是为web开发者创造的,在CSS和javascript中使用的一个抽象的层 在pc端,css像素和物理像素是1:1的关系;而在移动端,由于类似retina的各种高清屏的出现,css像素和物理像素的关系一般是2:1或者3:1,即1个物理像素容纳2到3个css像素,实现高清的效果。一般移动端页面的开发流程是:设计人员以某个机型作为标准,设计好UI。前端开发针对这个机型的UI做开发,然后其它机型相对的去等比例缩放。这里以iphone6作为标准(因为实际开发中基本也是用它做设计),它的物理像素为750x1334,css像素为375*667,假设UI上图片a的宽度为140,那么如何把它转换成以rem为单位的值呢?现在屏幕宽度是已知的10rem,要求UI上宽140的rem值,假设为X,由下图可以很容易的得到比例关系: ...

July 3, 2019 · 1 min · jiezi

使用Angular7开发一个Radio组件

一、准备工作Angular7(以下简称ng7),已经跟之前版本大有不同。新建工程后,可方便创建library(简称lib),lib是什么呢?就是一个npm包的源码包。npm作为强大的包管理器,已经成为很多FEer分享智慧成果的法器。本文主要介绍本人写的一个radio组件。 二、开发组件radio过程1、使用ng cli,新建工程,创建lib// 安装ng clinpm install -g @angular/cli// 新建工程ng new ng-project// 进入ng-project 创建一个libng generate library radio2、生成结构如图所示 接下来开始写组件 3、radio结构如下<!--说明:这其实是一个radio-group 因为radio一般都是分组使用,这里有几个注意点1、组内radio的name属性保持一致、组外保持唯一2、通过checked属性来设置radio的选中状态,一定不要写成[attr.checked]--><div class="input-wrap" [class.hor]="horizontal"> <div class="custom-radio" *ngFor="let item of data; let i=index"> <input #input class="custom-input" [name]="name" id="{{'radio_'+name+i}}" type="radio" [value]="item.value" (click)="clickHandler(item.value)" [checked]="item.value === value" [disabled]="disabled"> <label class="custom-label" for="{{'radio_'+name+i}}">{{item.name}}</label> </div></div>4、radio组件主体代码如下export class RadioGroupComponent implements ControlValueAccessor { /* radio 数组 */ @Input() data: Radio[] = []; /* radio 类型 原生或者按钮类型*/ @Input() type: string; /* name标识 */ @Input() name: string = this.idSer.generate().replace(/-/g, '_'); /* 水平排列 */ @Input() horizontal: boolean; /* 禁用 */ @Input() disabled: boolean; /* radio 值 */ @Input() value: any; constructor(private idSer: IdService) { } clickHandler(val: any) { this.value = val; // 更改control的值 this.controlChange(this.value); this.controlTouch(this.value); } writeValue(value: any): void { this.value = value; } registerOnChange(fn: Function): void { this.controlChange = fn } registerOnTouched(fn: Function): void { this.controlTouch = fn } private controlChange: Function = () => { } private controlTouch: Function = () => { }}说明:其实组件代码不是很多,但是应该注意到,我们继承了ng的一个interface ControlValueAccessor,这里我觉的是比较值得侃的地方。这是ng的一个forms API,可以方便原生DOM和ng forms传值。在组件元数据中这样定义 ...

July 2, 2019 · 1 min · jiezi

StepByStep高频面试题深入解析-周刊06

不积跬步无以至千里。 关于【Step-By-Step】Step-By-Step (点击进入项目) 是我于 2019-05-20 开始的一个项目,每个工作日发布一道面试题。每个周末我会仔细阅读大家的答案,整理最一份较优答案出来,因本人水平有限,有误的地方,大家及时指正。 如果想 加群 学习,可以通过文末的公众号,添加我为好友。 本周面试题一览:原型链继承的基本思路是什么?有什么优缺点?借用构造函数和组合继承基本思路是什么?有什么优缺点?原型式继承的基本思路是什么?有什么优缺点?寄生式继承的基本思路是什么?有什么优缺点?寄生组合式继承的基本思路是什么?有什么优缺点?本周是继承专题,在开始之前,需要先了解构造函数、原型和原型链的相关知识。 构造函数构造函数和普通函数的区别仅在于调用它们的方式不同,任何函数,只要通过 new 操作符来调用,那它就可以作为构造函数;任何函数,如果不通过 new 操作符来调用,那么它就是一个普通函数。 实例拥有 constructor(构造函数) 属性,该属性返回创建实例对象的构造函数。 function Person(name, age) { this.name = name; this.age = age;}var Yvette = new Person('刘小夕', 20);console.log(Yvette.constructor === Person); //true有一点需要说明的是,除了基本数据类型的 constructor 外( null 和 undefined 无 constructor 属性),constructor 属性是可以被重写的。因此检测对象类型时,instanceof 操作符比 contsrutor 更可靠一些。 function Person(name) { this.name = name;}function SuperType() { }var Yvette = new Person('刘小夕');console.log(Yvette.constructor); //[Function: Person]Yvette.constructor = SuperType;console.log(Yvette.constructor); //[Function: SuperType]原型我们创建的每个函数都有 prototype 属性,这个属性指向函数的原型对象。原型对象的用途是包含可以由特定类型的所有实例共享的属性和方法。 ...

July 2, 2019 · 3 min · jiezi

JavaScript正则需要注意的地方

exec()和match()区别当采用非全局匹配的时候,两个方法的返回值完全一样。match和exec都只匹配一次,且都会把分组抽出来放到数组后面 (function(){ let str="antzoane"; let reg=/(a)(n)/; console.log(str.match(reg)); console.log(reg.exec(str)); })(); 当为全局匹配的时候,match方法返回一个存放所有匹配内容的数组(无视子表达式的匹配)。exex方法返回数组不会存储所有的匹配,仅存储第一个匹配到的内容(存储在数字第一个元素),第二个元素存储第一个子表达式匹配到的内容,第三个元素存储第二个子表达式匹配到的内容,以此类推 (function(){ let str="antzoane"; let reg=/a(n)/g; console.log(str.match(reg)); console.log(reg.exec(str)); //再次调用从上次的lastindex开始匹配; console.log(reg.exec(str)); })(); match()和分组匹配 var reg = /(\d{4})-(\d{2})-(\d{2})/; var dateStr = '2018-04-18'; var s=dateStr.match(reg); console.log(s)//arr[0]是匹配的结果,arr[1]是第一个()里的匹配内容,全局匹配不会返回()里的内容 var str="hello my name is ben &nbsp;&nbsp;,this is &nbsp;"; var reg2=/&nbsp;{1,}/g; var reg22=/(&nbsp;){1,}/g//()内看成一个整体去匹配 console.log(str.match(reg2)); console.log(str.match(reg22)); replace()和分组捕获全部匹配添加修饰 var str="0816-2323263"; var reg=/(\d+)(-)(\d+)/g; var str2=str.replace(reg,"($1)-$3");//全部匹配添加修饰 console.log(str2);//(0816)-2323263(?<name>)与(?:exp)var str1="123478basd-12aaaaa"; var reg1=/(\d+)([a-z]+)(\d+)(?<rename>[a-z]+)/g; var str21=str1.replace(reg1,"$1hhhhh$<rename>");//(?<name>)捕获文本到名称为name的组里 (?:exp)匹配exp,不捕获匹配的文本,也不给此分组分配组号 console.log(str21);//123478basd-12aaaaa匹配需要删除的部分然后置空 var str23="123478basd12asdsa"; var reg2=/[a-z]+/g; var str22=str23.replace(reg2,"");//匹配需要删除的部分然后置空 console.log(str22);//12347812贪婪与懒惰在量词后面加个问号表示懒惰,尽可能少的匹配 var str="abc8defghij7klngon8qrstwxy7"; var reg1=/8[a-zA-Z0-9]*7/; var reg2=/8[a-zA-Z0-9]*?7/; var reg3=/8[a-zA-Z0-9]+?/; var res1=str.match(reg1); var res2=str.match(reg2); var res3=str.match(reg3); console.log(res1); console.log(res2); console.log(res3); ...

July 1, 2019 · 1 min · jiezi

2019年7月所遇知识点整理

*注:本文章是在工作过程中所接触的知识点的整理,涉及的东西比价杂乱,如有错误之处,欢迎纠错与指导

July 1, 2019 · 1 min · jiezi

jQuery之模拟实现animate下

前言:在上篇的基础上,接入doAnimation() 逻辑图: 实现: <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>jQuery之$().animate()的实现</title></head><body><!--<script src="jQuery.js"></script>--><div id="A" style="width:100px;height:50px;background-color: deeppink">这是A</div><script> // (function(a){ // console.log(a) //name // })('name') // // (function (b) { // console.log(b) //function(){console.log('name')} // })(function () { // console.log('name') // }) //匿名函数自调用,下面好长好长的function就是$ //也就是说$是一个function(){xxx} (function($) { window.$ = $; })( //这里也是匿名函数自调用 //本质就是经过一系列操作得到chenQuery并作为参数$,赋值给window.$ function() { //匹配ID let rquickExpr = /^(?:#([\w-]*))$/; //jQuery初始化 function chenQuery(selector) { return new chenQuery.fn.init(selector); } function getStyles(elem) { return elem.ownerDocument.defaultView.getComputedStyle(elem, null); } //模仿swing动画效果 //两头慢,中间快 function swing(p) { return 0.5 - Math.cos(p * Math.PI) / 2; } //创建动画缓动对象// function Tween(value, prop, animation) { this.elem=animation.elem; this.prop=prop; this.easing= "swing"; //动画缓动算法 this.options=animation.options; //获取初始值 this.start=this.now = this.get(); //动画最终值 this.end= value; //单位 this.unit="px" } Tween.prototype = { //获取元素的当前属性 get: function() { let computed = getStyles(this.elem); let ret = computed.getPropertyValue(this.prop) || computed[this.prop]; return parseFloat(ret); }, //运行动画 run:function(percent){ let eased //根据缓动算法改变percent this.pos = eased = swing(percent); //获取具体的改变坐标值 this.now = (this.end - this.start) * eased + this.start; //最终改变坐标 this.elem.style[this.prop] = this.now + "px"; return this; } } //创建开始时间 function createFxNow() { setTimeout(function() { Animation.fxNow = undefined; }); return (Animation.fxNow = Date.now()); } let inProgress function schedule() { //inProgress是判断整个动画流程是否结束的标志 //当inProgress=null时,整个动画结束 if ( inProgress ) { //走这边 //使用requestAnimationFrame来完成动画 //递归 window.requestAnimationFrame( schedule ); /*执行动画帧*/ Animation.fx.tick(); } } // 动画核心函数 function Animation(elem, options, optall,func,){ //动画对象 let animation = { elem:elem, props:options, originalOptions:optall, options:optall, //动画开始时间 startTime:Animation.fxNow || createFxNow(), //存放每个属性的缓动对象,用于动画 tweens:[] } //生成属性对应的动画算法对象 for (let k in options) { // tweens保存每一个属性对应的缓动控制对象 animation.tweens.push( new Tween(options[k], k, animation) ) } //动画状态 let stopped; //动画的定时器调用包装器 //单帧循环执行 let tick = function() { if (stopped) { return false; } //动画时间算法 let currentTime = Animation.fxNow || createFxNow, //动画运动时间递减 remaining = Math.max(0, animation.startTime + animation.options.duration - currentTime), //百分比 temp = remaining / animation.options.duration || 0, percent = 1 - temp; let index = 0, length = animation.tweens.length; //执行动画改变 for (; index < length; index++) { //percent改变值 animation.tweens[index].run(percent); } //当进度不到100%时,继续绘制动画帧 if (percent < 1 && length) { return remaining; } //当结束时通知单个动画结束 tick.complete() return false } tick.elem = elem; tick.anim = animation //这个是自定义的属性,也就是单个动画结束的标志 tick.complete = func //开始执行下个动画 Animation.fx.timer(tick) } //用于requestAnimationFrame调用 Animation.timers =[] Animation.fx = { //开始动画队列,不是帧队列 //Animation.tick() timer: function(timer,) { Animation.timers.push(timer); if (timer()) { //开始执行动画 Animation.fx.start(); // func() } // else { // Animation.timers.pop(); // } }, //开始循环 start: function(func) { if ( inProgress ) { return; } //动画开始即为运行中,加上锁 inProgress = true; //运行 schedule(); // func() }, //停止循环 stop:function(){ inProgress = null; }, //动画帧循环的的检测 tick: function() { var timer, i = 0, timers = Animation.timers; Animation.fxNow = Date.now(); for (; i < timers.length; i++) { timer = timers[i]; if (!timer() && timers[i] === timer) { //如果完成了就删除这个动画 timers.splice(i--, 1); } } if (!timers.length) { Animation.fx.stop(); } Animation.fxNow = undefined; } } //假设是在数据缓存中存取队列 const Queue=[] //数据缓存 const dataPriv={ get:function (type) { if(type==='queue') return Queue }, } const dequeue=function() { const Queue=dataPriv.get("queue") let fn = Queue.shift() //当单个动画结束后,执行下个动画 const next = function() { dequeue(); } if ( fn === "inprogress" ) { fn = Queue.shift(); } if (fn) { Queue.unshift( "inprogress" ); /*执行doAnimation方法,doAnimation(element, options,function() {firing = false;_fire();})*/ /*fn的参数就是形参func*/ /*func方法是用来通知上个动画结束,下个动画运行的重要function*/ //func的作用是用来通知动画执行结束,并继续执行下一个动画 const func=function() { next(); } fn(func); } } //省略type const queue=function(element, options, callback, ) { //模仿从数据缓存中得到的队列,直接写Queue.push也行 const Queue=dataPriv.get("queue") //向动画队列中添加doAnimation触发器 Queue.push(function(func) { //doAnimation callback(element, options, func); }); //如果没有动画在运行,运行动画 //动画锁inprogress if(Queue[0]!=='inprogress'){ dequeue() } } /*动画*/ const animation = function(element,options) { const doAnimation = function(element, options, func) { // const width = options.width /*===这里面定义了动画的算法,也就是Animation实现的地方===*/ // 默认动画时长2s // element.style.transitionDuration = '400ms'; // element.style.width = width + 'px'; /*监听单个动画完结*/ //transitionend 事件在 CSS 完成过渡后触发 // element.addEventListener('transitionend', function() { // func() // }); //动画的默认属性 let optall={ complete:function(){}, old:false, duration: 400, easing: undefined, queue:"fx", } let anim=Animation(element, options, optall,func) } //每调用一次animation,就入一次队 return queue(element, options,doAnimation,); } //为chenQuery的fn和prototype原型属性 赋 animate属性 chenQuery.fn = chenQuery.prototype = { //也可以直接把animation里的代码放这里来,但这样就太长了,降低了可读性 animate: function(options) { animation(this.element, options); //注意返回的是this,也就是$("#A"),这样就能继续调用animate方法 // 也就是链式调用 return this; } } //为chenQuery的fn属性添加init方法 const init = chenQuery.fn.init = function(selector) { // ["#A", "A",groups: undefined,index: 0,input: "#A"] const match = rquickExpr.exec(selector); //这边默认是只找id的元素 const element = document.getElementById(match[1]) //this指chenQuery.fn.init方法 //为该方法添加element属性 this.element = element; //返回chenQuery.fn.init return this; } //挺绕的,再将init的原型等于chenQuery.fn方法 init.prototype = chenQuery.fn; //chenQuery本身是一个function(){} // chenQuery{ //init能调用fn,fn能调用init // fn:{ // animate:function(){}, // init:function(){}, // // init.prototype=fn // }, // prototype:{ // animate:function(){}, // } // } return chenQuery; }()); const A = document.querySelector('#A'); //在异步调用中,进行同步调用 //动画是异步的 A.onclick = function() { //就是连续调用animation.add() $('#A').animate({ 'width': '500' }).animate({ 'width': '300' }).animate({ 'width': '1000' }); };</script></body></html>运行结果: ...

July 1, 2019 · 4 min · jiezi

我们开发者有自己的导航网站啦-wanghangcomcn-Beta版正式上线

一直想把本地自己用的导航发布到线上,由于自身UI不过关,长期以来只是停留在“筹备”之中 ̄▽ ̄。最近把界面简单做了一下美化,正式发布上来了,不过是简化版本,有许模块没有加入其中,后期会陆续更新,敬请期待!心愿是为我们开发者、前端以及UI设计师提供一个属于我们自己的导航主页。希望大家多多包含、多多提提意见,多多支持,感谢!围观网址:www.wanghang.com.cn,欢迎大家拍砖

July 1, 2019 · 1 min · jiezi

整理DOM事件相关知识点

DOM事件相关内容当用户与浏览器发生的一些交互时, 如果希望去获得用户行为, 就需要借助事件来完成. 事件部分内容在 JS中重要性不言而喻. 罗列需要了解与事件相关的知识如下: 这也是面试中遇到的问题. DOM 事件的级别DOM 事件模型DOM 事件流DOM 事件处理程序描述DOM事件捕获(冒泡)的具体流程Event对象常见的应用自定义事件事件级别DOM0DOM2DOM3DOM 事件模型事件冒泡事件捕获什么是事件流要想明白事件流,必须先懂的这几个知识点 事件冒泡事件捕获先来看一个有趣的问题, 这是 4 代浏览器(IE4)开发团队遇到一个的问题: What part of the Webpage owns a specific event?页面的哪一部分会拥有某个特定的事件? 要想明白这个问题可以想象成在一个页面上画了一组同心圆, 当手指放在中间时,它不仅在一个圆圈内,而且在所有的圆圈内。如下图所示: 这就是浏览器事件的工作原理, 当你点击一个按钮时, 不仅单击按钮,还单击包含的容器和整个页面。 事件生命周期, 分为三个阶段: capturing (捕获), target (目标), bubbling (冒泡). 而这三个阶段也是构成事件流基本部分. 这种处理思想, 在现在流行 NodeJS 后端框架 Koa 对中间件的处理模式也是基于这种, 熟悉Koa或许对这洋葱图并不会陌生: 先来熟悉事件的模型: Javascript Events: Event bubbing (事件冒泡)事件冒泡: 既事件开始由最具体的元素接收,然后逐级向上传播最后到达 Document 对象 或 window 上. 先来看一个简单的示例, 代码如下: <!DOCTYPE HTML> <html> <head> <title>......</title> </head> <body> <div id="demo"> Press here.</div> </body> </html> var target = document.getElementById("demo"); window.addEventListener("click", function(){ console.log("window bubbling"); }); document.addEventListener("click", function(){ console.log("document bubbling"); }); document.documentElement.addEventListener("click", function(){ console.log("html bubbling"); }); document.body.addEventListener("click", function(){ console.log("body bubbling"); }); target.addEventListener("click", function(){ console.log("target bubbling"); });控制台打印输出如下: ...

June 30, 2019 · 2 min · jiezi

内敛元素间隙问题

行内元素之间会产生间隙bug问题的场景:当行内元素之间有“回车”、“tab”、“空格”时就会出现间隙。注:常见的行内元素有:img、span、a、b等 解决方法写在一行,之间不要有空格之类的符号(不建议,代码混乱,不直观) <div><a>1</a><a>2</a><span>33333</span><span>44444</span><em>555555</em></div>父元素设置font-size:0,然后内敛元素上再设置具体的字体大小。div{font-size:0;}span{font-size:16px;}float浮动个人认为最直接的方法,当然是在适当的场景中,因为过度的浮动会产生需要清除浮动的必要 如有更好的方法欢迎大家留言,谢谢~~~

June 30, 2019 · 1 min · jiezi

移动端基本概念

1. 物理像素物理像素是手机的分辨率,在同一个手机上,物理像素是出厂就设置好的,如iPhone6的物理像素是750*1334 2. 逻辑像素逻辑像素是手机的逻辑分辨率,包括css像素3. 设备像素比物理像素/逻辑像素=DPR4. viewpoint概念用于设置页面宽度;width=device-width,此时页面的宽度恰好等于设备的浏览器宽度width=640,此时页面的宽度大于设备浏览器宽度,会出现横向滚动条initial-scale:页面的初始缩放值,1不进行缩放,0.5放大两倍

June 30, 2019 · 1 min · jiezi

vue实现自定义H5视频播放器

前言前段时间基于vue写了一个自定义的video播放器组件,踩了一些小坑, 这里做一下复盘分享出来,避免日后重复踩坑... 设计阶段这里就直接放几张完成后的播放状态图吧,界面布局基本就是flex+vw适配一把梭,也比较容易. 需要实现的几个功能基本都标注出来了; 除了还有一个视频加载失败的...下面就这届上代码了;刚开始构思的时候考虑了一下功能的实现方式: 一是用原生的DOM操作,获取video元素后,用addEventListener来监听; 二是用vue的方式绑定事件监听; 最后图方便采用了两者结合的方式,但是总感觉有点乱, 打算后期再做一下代码格式优化. video组件实现过程组件模板部分主要是播放器的几种播放状态的逻辑理清楚就好了, 即: 播放中,缓存中,暂停,加载失败这几种情况,下面按功能分别说一下 <template> <div class="video-player"> <!-- 播放器界面; 兼容ios controls--> <video ref="video" v-if="showVideo" webkit-playsinline="true" playsinline="true" x-webkit-airplay="true" x5-video-player-type="h5" x5-video-player-fullscreen="true" x5-video-orientation="portraint" style="object-fit:fill" preload="auto" muted="true" poster="https://photo.mac69.com/180205/18020526/a9yPQozt0g.jpg" :src="src" @waiting="handleWaiting" @canplaythrough="state.isLoading = false" @playing="state.isLoading = false, state.controlBtnShow = false, state.playing=true" @stalled="state.isLoading = true" @error="handleError" >您的浏览器不支持HTML5</video> <!-- 兼容Android端层级问题, 弹出层被覆盖 --> <img v-show="!showVideo || state.isEnd" class="poster" src="https://photo.mac69.com/180205/18020526/a9yPQozt0g.jpg" alt > <!-- 控制窗口 --> <div class="control" v-show="!state.isError" ref="control" @touchstart="touchEnterVideo" @touchend="touchLeaveVideo" > <!-- 播放 || 暂停 || 加载中--> <div class="play" @touchstart.stop="clickPlayBtn" v-show="state.controlBtnShow"> <img v-show="!state.playing && !state.isLoading" src="../../assets/video/content_btn_play.svg" > <img v-show="state.playing && !state.isLoading" src="../../assets/video/content_btn_pause.svg" > <div class="loader" v-show="state.isLoading"> <div class="loader-inner ball-clip-rotate"> <div></div> </div> </div> </div> <!-- 控制条 --> <div class="control-bar" :style="{ visibility: state.controlBarShow ? 'visible' : 'hidden'}"> <span class="time">{{video.displayTime}}</span> <span class="progress" ref="progress"> <img class="progress-btn ignore" :style="{transform: `translate3d(${video.progress.current}px, 0, 0)`}" src="../../assets/video/content_ic_tutu.svg" > <span class="progress-loaded" :style="{ width: `${video.loaded}%`}"></span> <!-- 设置手动移动的进度条 --> <span class="progress-move" @touchmove.stop.prevent="moveIng($event)" @touchstart.stop="moveStart($event)" @touchend.stop="moveEnd($event)" ></span> </span> <span class="total-time">{{video.totalTime}}</span> <span class="full-screen" @click="fullScreen"> <img src="../../assets/video/content_ic_increase.svg" alt> </span> </div> </div> <!-- 错误弹窗 --> <div class="error" v-show="state.isError"> <p class="lose">视频加载失败</p> <p class="retry" @click="retry">点击重试</p> </div> </div></template>播放器初始化这里有个坑点我就是当父元素隐藏即display:none时,getBoundingClientRect()是获取不到元素的尺寸数值的,后来查了MDN文档,按上面说的改了一下border也没有用,最后尝试设置元素visibility属性为hidden后发现就可以获取了.getBoundingClientRect() : 返回元素的大小及其相对于视口的位置, 这个api在计算元素相对位置的时候挺好用的. ...

June 30, 2019 · 4 min · jiezi

H5-canvas生成图片并上传文件转成PDF下载canvas文字排版

H5 canvas生成图片并上传文件转成PDF下载最近遇到一个业务需求,在小程序端定制预览功能,并在预览的图片中使用指定的外部字体。将预览的图片上传OSS,后端生成PDF,在管理系统中下载。但是…………,经过实践发现,小程序尽管做了分包处理,依旧不能在本地存放字体包,把字体放OSS上返回,但是出现跨域,尽管配置了允许跨域,依旧不行。而且!!!小程序的canvas API没法设置字体,没有h5中canvas中的context.font = '字体名称'方法。最终决定曲线救国,放弃小程序端的预览生成canvas功能,将canvas引入字体,生成图片等操作放在管理系统中,采用原生canvas来实现。 技术要点canvas文字排版canvas设置指定背景颜色canvas引入外部字体canvas绘制文字图片将canvas生成的base64图片转成file上传(这里根据后端协商,此处后端要求)将图片生成PDF,并点击批量下载实现步骤canvas文字排版在一般HTML容器中,如果要实现文字的排版很容易。比如:实现文本超出自动换行,默认文本超出容器宽度就会自动换行,也可以使用word-wrap:break-word实现强制换行。实现文字竖排,有几种方式: 给文本容器设置writing-mode样式:(存在兼容性问题)writing-mode:vertical-rl;//垂直方向自右而左的书写方式。即 top-bottom-right-left或者writing-mode:vertical-lr;//垂直方向内内容从上到下,水平方向从左到右具体效果如图: 但是这个对于浏览器也存在一定兼容性问题,使用的时候需要注意。 使用宽度控制换行:(不存在兼容性,推荐方式)设置每行的宽度为一个字大小,利用文本超出默认换行的特性,或者设置超出强制换行,实现文本竖排。 利用br标签实现或者每个文字存放一个标签实现换行:(很死板的写法,比较low,不推荐)给每个文字后添加br标签,或者每个文字放一个标签,这样写灵活性不高,非常不推荐! 在canvas中实现文字排版实现文字横排canvas中,如果文本超出canvas大小,并不会自动换行,会直接在超出的后面继续绘制成一排。canvas中也没有直接可以设置换行的api,那该怎么实现换行呢?可以通过js控制,通过计算当前绘制文字的x坐标,如果x坐标大于canvas的宽度,将x坐标赋值为0(绘制的起始点x坐标),y坐标累加一个文字的高度,从而实现文本换行。 实现文字竖排竖排的逻辑和横排是一样的。文字竖排只是y坐标累加,趟超过canvas的高度时,将y坐标赋值为0(绘制的起始点y坐标),x坐标累加一个文字的高度,从而实现竖排且文本换行。 部分代码片段 /** * canvas绘制文字 * @param {CanvasRenderingContext2D对象} context * @param {绘制内容} text * @param {起始点x坐标制} x * @param {起始点y坐标制} y */ drawTextVertical(context, text, x, y) { let startX = x, startY = y; //记录开始的位置,用于文字换行赋值 let spaceCount = 0; let arrText = text.trim().split(''); let formatText = text.replace(/\//g, '').split(''); // 去掉单斜杠 let align = context.textAlign; let baseline = context.textBaseline; context.textAlign = 'center'; context.textBaseline = 'middle'; context.font = 'Pacifico' // 开始逐字绘制 arrText.forEach(function (letter, index) { // 确定下一个字符的纵坐标位置 // 是否需要旋转判断 let code = letter.charCodeAt(0); // 计算文字间距 let letterWidth = 22 * 2.3; if (code <= 256) { context.translate(x, y); // 英文字符,旋转90° context.rotate(90 * Math.PI / 180); context.translate(-x, -y); } if (code !== 47) context.fillText(letter, x, y); // 旋转坐标系还原成初始态 context.setTransform(1, 0, 0, 1, 0, 0); // 单斜杠换行或者长度超过8 此处要过滤在第9字是换行的符号的情况 if ((code === 47 && !spaceCount) || (!spaceCount && index && index % 7 === 0)) { // 单斜杠/ 代表换行 charCode=47 spaceCount += 1; y = startY; x = index ? (startX + letterWidth) : x; startX = x; } else if (code !== 47) { // 如果是空格 减少字间距 if (code !== 32) { y = y + letterWidth; } else { y = y + letterWidth / 2 } } }); // 水平垂直对齐方式还原 context.textAlign = align; context.textBaseline = baseline; } ...

June 30, 2019 · 3 min · jiezi

Today2019年6月29日

Python数据类型 三种分别是:字符串(string)、整数(integer)、浮点数(float) eg:str='字符串'、int=33、float=3.24 区别:字符串的识别方式非常简单——有层名为【引号】的皮,只要是被【单/双/三引号】这层皮括起来的内容,不论那个内容是中文、英文。只要是被括起来的,就表示是字符串类型。整数其实和数学中定义的一样:是正整数、负整数和零的统称,是没有小数点的数字。注:没有引号 浮点数非常好识别,它比整数多了一个小数点『.』,比如下列代码中的数字都是浮点数。数据的应运 四则运算:先算括号里的在乘除加减 字符串的拼接:+ 数据类型的查询——type()函数 who = '我的'action = '是'destination = '镜像世界'number = 153code = 3.32print(type(who))print(type(action))print(type(destination))print(type(number))print(type(code))结果: bash:124$ python ~/classroom/apps-1-id-5cd9765619bbcf0001554798/124/main.py <class 'str'> <class 'str'> <class 'str'> <class 'int'> <class 'float'> 作用:可以验证数据类型 sessionStorage <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>菜鸟教程(runoob.com)</title> </head> <body> <div id="result"></div> <script> // 检测浏览器支持 if (typeof(Storage) !== "undefined") { // 存储 sessionStorage.setItem("lastname", "Smith"); // 检索 document.getElementById("result").innerHTML = sessionStorage.getItem("lastname"); } else { document.getElementById("result").innerHTML = "Sorry, your browser does not support Web Storage..."; } </script> </body> </html>可以在Application中的sessionStorage查看 ...

June 29, 2019 · 1 min · jiezi

jQuery之模拟实现animate上

根据上图实现除doAnimation外的逻辑: <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>jQuery之$().animate()的实现</title></head><body><script src="jQuery.js"></script> <div id="A" style="width:100px;height:50px;background-color: deeppink">这是A</div><script> //匿名函数自调用,下面好长好长的function就是$ //也就是说$是一个function(){xxx} (function($) { window.$ = $; })( //这里也是匿名函数自调用 //本质就是经过一系列操作得到chenQuery并作为参数$,赋值给window.$ function() { //匹配ID let rquickExpr = /^(?:#([\w-]*))$/; //jQuery初始化 function chenQuery(selector) { return new chenQuery.fn.init(selector); } //假设是在数据缓存中存取队列 const Queue=[] //数据缓存 const dataPriv={ get:function (type) { if(type==='queue') return Queue }, } const dequeue=function() { const Queue=dataPriv.get("queue") let fn = Queue.shift() //当单个动画结束后,执行下个动画 const next = function() { dequeue(); } if ( fn === "inprogress" ) { fn = Queue.shift(); } if (fn) { Queue.unshift( "inprogress" ); /*执行doAnimation方法,doAnimation(element, options,function() {firing = false;_fire();})*/ /*fn的参数就是形参func*/ /*func方法是用来通知上个动画结束,下个动画运行的重要function*/ //func的作用是用来通知动画执行结束,并继续执行下一个动画 const func=function() { next(); } fn(func); } } //省略type const queue=function(element, options, callback, ) { //模仿从数据缓存中得到的队列,直接写Queue.push也行 const Queue=dataPriv.get("queue") //向动画队列中添加doAnimation触发器 Queue.push(function(func) { //doAnimation callback(element, options, func); }); //如果没有动画在运行,运行动画 //动画锁inprogress if(Queue[0]!=='inprogress'){ dequeue() } } /*动画*/ const animation = function(element,options) { const doAnimation = function(element, options, func) { const width = options.width /*===这里面定义了动画的算法,也就是Animation实现的地方===*/ // 默认动画时长2s element.style.transitionDuration = '400ms'; element.style.width = width + 'px'; /*监听单个动画完结*/ //transitionend 事件在 CSS 完成过渡后触发 element.addEventListener('transitionend', function() { func() }); } //每调用一次animation,就入一次队 return queue(element, options,doAnimation,); } //为chenQuery的fn和prototype原型属性 赋 animate属性 chenQuery.fn = chenQuery.prototype = { //也可以直接把animation里的代码放这里来,但这样就太长了,降低了可读性 animate: function(options) { animation(this.element, options); //注意返回的是this,也就是$("#A"),这样就能继续调用animate方法 // 也就是链式调用 return this; } } //为chenQuery的fn属性添加init方法 const init = chenQuery.fn.init = function(selector) { // ["#A", "A",groups: undefined,index: 0,input: "#A"] const match = rquickExpr.exec(selector); //这边默认是只找id的元素 const element = document.getElementById(match[1]) //this指chenQuery.fn.init方法 //为该方法添加element属性 this.element = element; //返回chenQuery.fn.init return this; } //挺绕的,再将init的原型等于chenQuery.fn方法 init.prototype = chenQuery.fn; //chenQuery本身是一个function(){} // chenQuery{ //init能调用fn,fn能调用init // fn:{ // animate:function(){}, // init:function(){}, // // init.prototype=fn // }, // prototype:{ // animate:function(){}, // } // } return chenQuery; }()); const A = document.querySelector('#A'); //在异步调用中,进行同步调用 //动画是异步的 A.onclick = function() { //就是连续调用animation.add() $('#A').animate({ 'width': '500' }).animate({ 'width': '300' }).animate({ 'width': '1000' }); };</script></body></html> ...

June 29, 2019 · 2 min · jiezi

关于indexOf的发散思维

在发散思维前先介绍一下基本知识; 定义与用法:indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置。 这里基本用法大家一般都清楚,一般在实际工作中常与数组的方法合用来对数组进行一些操作。例如: var arr=['Mike','Chen Jie','Amy','Sarah'];//将Amy从数组中删除arr.splice(arr.indexOf('Amy'),1)//将Amy替换为Zhang Peng,并追加Wu Yifan,Miss Whitearr.splice(arr.indexOf('Amy'),1,'Zhang Peng','Wu Yifan','Miss White')下面介绍一下第二个参数的用法,可指定在字符串中开始检索的位置,这个可以用来快速查找字符串中出现某个字母的位置及次数。例如: var str='what is your name? my name is Jhon.'var positions=new Array();//初始化索引var index=str.indexOf('m');while(index>-1){ positions.push(index); //改变索引 index=str.indexOf('m',index+1);}console.log(positions)// [15, 19, 24]这个例子主要是通过不断增加str.indexOf的初始查找的位置,从而遍历了整个字符串。下面介绍一个indexOf的兄弟方法: 定义与用法lastIndexOf() 方法可返回一个指定的字符串值最后出现的位置,在一个字符串中的指定位置从后向前搜索。参数上差不多,这里不做太多介绍,lastIndexOf和indexOf的区别就是lastIndexOf是从后往前查,可以用于检测字符串中某个字母的唯一性; var str='hello world';str.lastIndexOf('w')===str.indexOf('w')这里如果结果为true,并且不等于-1的话可以验证字母的唯一性;

June 29, 2019 · 1 min · jiezi

VueRouter路由模式和install过程

单页应用(SPA, Single Page Application)的整个Web系统由一个html文件,通过Ajax和后端进行数据交互,通过一些特殊手段去加载渲染页面的不同部分,使得无需刷新整体页面,,就像使用app一样,极大的提升了用户使用体验,在Vue生态中,就是利用Vue的核心插件-Vue-Router来实现Web界面的路由跳转,so,本文就是通过学习Vue-Router,了解Vue-Router完成SPA开发的实现具体原理。 Web路由简介 先简单说一下路由,早期Web系统路由主要是服务器后端实现,熟悉前后端开发的朋友就知道,在服务器端,通过路由表映射到相应的方法,并执行相应的动作,比如我们想要请求API数据、新页面、文件等: "/" -> goHtml()"/api/users" -> queryUsers() 客户端实现路由主要就有两种方式: 1. 基于Web Url的hash2. 基于Hishtory API基于Web Url的hash Url中的hash值是“#”号后面的参数值,比如http://www.example.com/index.html#location1里面的值localtion1, 主要有如下一些特性(之前看到公司项目的Url中带有“#”,虽然有点莫名,但都没去想想咋来的,汗): 1. Url中#后的内容不会发送到服务器;2. hash值的改变会保存到浏览器的历史浏览记录中,可通过浏览器的回退按钮查看;3. hash值是可读写的,可通过window.location.hash获取到hash值,利用onhashchange监听hash值的变化(Vue-Router里的hash模式就是在onhashchange中的回调事件中完成路由到界面的更新渲染)。基于Hishtory API 基于hash模式虽然方便,但带有#号,有同学就会觉这样的Url有点丑啦,为了和同向服务器后端请求的Url风格保持一致,就可以使用Hishtory API模式了。使用基于Hishtory API主要是操作HTML5提供的操作浏览器历史记录API,可以实现地址无刷新更新地址栏,例如: // pushState state: 用于描述新记录的一些特性。// 这个参数会被一并添加到历史记录中,以供以后使用。// 这个参数是开发者根据自己的需要自由给出的。// pushState作用相当于修改“#”后面的值window.history.pushState(state, "title", "/userPage");// 比如浏览器后退window.addEventListener("popstate", function(e) { var state = e.state; // do something...});// 与pushState相对仅进行Url替换而不产生新的浏览记录的replaceState方法window.history.replaceState(null, null, "/userPage");两种模式对比 我们来简单对比一下这两种模式的一些特点: |模式 VS | hash | Hishtory API | | ------ | ------ | ------ | | 美观程度 | 公认略丑,带#号 | 相对美观 | | 兼容性 | 好 | 需要浏览器支持HTML5 | | 错误URL后端支持 | 否 | 是 | ...

June 29, 2019 · 2 min · jiezi

带着canvas去流浪10文字烟花

示例代码托管在:http://www.github.com/dashnowords/blogs博客园地址:《大史住在大前端》原创博文目录 华为云社区地址:【你要的前端打怪升级指南】 [TOC] 一. 文字烟花文字烟花的小控件是下面这样的效果,你或许在很多个人博客中见过: 这一节我们就来讲述一下这个小动画的实现方法。 二. 动画原理首先动画的主框架仍然是我们反复使用的逐帧动画框架,烟花生成以后的部分也不难理解,我们之前已经对物理碰撞进行过仿真,这里实际上就是模拟了带有初速度的自由落体。所以这个小动画里唯一的难点,就是如何根据文字生成烟花,只要做到这一步,其他的部分都比较容易实现。 2.1 像素操作这里就要用到canvas像素操作的API——context.getImageData( )了,它可以将画布上指定矩形区域以像素点的形式返回回来,像素数据挂载在返回对象的data属性上,它是一个一维的Uint8ClampedArray定型数组,每个值只能取0-255之间的整数,如果赋值超过这个范围,则自动修改为[0,255]而不会报错。这个一维数组是矩形区域的像素点数据逐行拼接在一起的,每4个点代表一个像素点的RGBA的颜色数据,最后一个通道是透明度数据,例如一个红色的像素点的数据就是[...,255,0,0,0....]。比如你截取了一个长为200像素高为10像素的矩形区域的数据点,那么就会得到一个200*10*4=8000个数据点的数组。 这是canvas非常重要的一个API,它的应用场景非常多,例如结合WebRTC输入的流数据来做视频弹幕,或者使用算法对像素数据进行加工实现各种各样的图片滤镜等,还可以使用离屏canvas来进行性能提升,具体的应用就留给你自己去探索喽。 2.2 烟花生成算法获取到像素数据后,我们就可以对其进行分析,分析算法如下: 将要获取像素的部分分成大小适中的网格,网格太小则渲染压力大,网格太大动画效果不好。遍历每一个网格,取出小方块区域内所有像素点,也可以一次性读取整个区域的像素点然后按小区域来取用,然后统计其中dirty的像素点数量(判断其对应的颜色值是否都为255,如果不是则判定为dirty),如果区域内脏点的比例超过一定阈值(示例中为60%)则判定该区域需要被烟花点替换。在需要生成烟花的区域以随机大小和颜色生成一个小球,并根据其位置指定水平初速度的方向,小球均受到竖直向下的重力影响。在帧动画中更新小球状态。2.3 计时器最后,我们还需要一个新的timer对象,之前我们接触到的精灵动画大都是连续的,每一帧都需要进行状态更新,而本节中时间文字的更新是离散的,一秒钟才更新一次,烟花由于有动画过程,也不太适合每秒都生成。所以我们需要在timer中实现一个内部计时器,每1秒更新一次渲染文字,每2秒触发一次。如果对时间精度要求较高,可以记录时间戳进行比对,如果精度要求不高,可以在update方法中递增直接对更新周期进行取模即可。 Timer类的定义如下: //计时器类class Timer{ constructor(){ this.lastTime = Date.now(); //初始化的时候记录一次时间 this.label = new Date(this.lastTime).Format('hh:mm:ss');//Format是自定义的格式化方法 this.step = 0;//标记是否刷新时间文字 this.shouldAnim = 0;//标记是否需要生成新的烟花 } update(){ this.step = (this.step + 1) % 60;//时间文字每60帧刷新一次 this.shouldAnim = (this.shouldAnim + 1) % 120;//烟花每120帧生成一次 if (!this.step) { this.lastTime = Date.now(); this.label = new Date(this.lastTime).Format('hh:mm:ss'); } } paint(ctx){ context.fillStyle = "#353535"; ctx.fillText(this.label, 200, 100); }}主框架部分的代码已经讲过非常多次,本文不再赘述。 ...

June 29, 2019 · 1 min · jiezi

Canvas裁剪图片截选框可拖拽

利用Canvas实现图片裁剪效果图 实现思路打开图片并将图片绘制到canvas中;利用canvas的drawImage()函数来裁剪图片;将canvas转化为Image即可。HTML代码:<div id="container"> <div id="btnDiv"> <button id="btn1">截图</button> <button id="btn2">确认截图</button> <button id="btn3">打开</button> </div> <div id="imgDiv"></div> <div id="clipImgDiv"></div></div>CSS代码CSS代码基本通过javaScript添加 <style> body { background-color: black; } </style>重点JavaScript代码变量定义、添加各事件按钮、容器等: let originWidth; // 图片原始宽度 let originHeight; // 图片原始高度 let container = document.getElementById('container'); let imgDiv = document.getElementById('imgDiv'); // 存放mycanvas let btnDiv = document.getElementById('btnDiv'); let clipImgDiv = document.getElementById('clipImgDiv'); // 显示裁剪所获的图片 let btn1 = document.getElementById('btn1'); // 截图按钮 let btn2 = document.getElementById('btn2'); // 确认截图按钮 let btn3 = document.getElementById('btn3'); // 打开文件按钮 var oRelDiv = document.createElement("div"); // 截图框 var scaleX = 1;// 图片宽度缩放比例(当前实际/原始) var scaleY = 1; // 图片高度缩放比例(当前实际/原始) //拖拽与拉伸方法 //拖拽拉伸所需参数 let params = { left: 0, top: 0, width: 0, height: 0, currentX: 0, currentY: 0, flag: false, kind: "drag" }; // CSS样式修改 container.style.display = 'flex'; container.style.flexDirection = 'column'; btnDiv.style.marginBottom = '20px'; btnDiv.style.height = '30px'; imgDiv.style.marginBottom = '20px'; // 创建canvas,用于显示被裁剪图片 var myCanvas = document.createElement('canvas'); myCanvas.setAttribute('id', 'myCanvas'); myCanvas.style.display = 'block'; /*myCanvas.style.position = 'absolute';*/ myCanvas.width = 600; myCanvas.height = 600; myCanvas.style.border = "1px solid #d3d3d3"; myCanvas.innerText = '您的浏览器不支持 HTML5 canvas 标签。'; myCanvas.style.zIndex = 'auto'; var ctx = myCanvas.getContext('2d'); // 被裁剪图片 var img = new Image(); img.src = './images/IMG_1550.jpg'; img.setAttribute('id', 'img'); img.width = 600; img.height = 600; img.onload = function () { console.log('onload()执行...'); ctx.drawImage(img, 0, 0, 600, 600); originWidth = img.naturalWidth; originHeight = img.naturalHeight; console.log('图片原始宽度=', originWidth); console.log('图片原始高度=', originHeight); }; // 裁剪得到的图片 let clipImg = new Image(); clipImg.src = ''; clipImg.style.height = '100px'; clipImg.style.width = '100px'; clipImg.alt = '裁剪获得图片...'; // input用于打开文件 let fileInput = document.createElement('input'); fileInput.setAttribute('multiple', 'multiple'); fileInput.setAttribute('type', 'file'); fileInput.setAttribute('id', 'fileInput'); /*btnDiv.appendChild(fileInput);*/ imgDiv.appendChild(myCanvas); /*clipImgDiv.appendChild(clipImg);*/一些简单的功能函数// 生成本地图片URL地址let getObjectURL = function (file) { let url = null; if (window.createObjectURL !== undefined) { // basic url = window.createObjectURL(file); } else if (window.webkitURL !== undefined) { // webkit or chrome url = window.webkitURL.createObjectURL(file); } else if (window.URL !== undefined) { // mozilla(firefox) url = window.URL.createObjectURL(file); } return url; }; // 获取指定元素DOM const ID = function (id) { return document.getElementById(id); }; //获取相关CSS属性方法 let getCss = function (o, key) { return o.currentStyle ? o.currentStyle[key] : document.defaultView.getComputedStyle(o, false)[key]; };打开本地图片可伸缩截图框实现思路: ...

June 28, 2019 · 7 min · jiezi

js数组中filtermapreducefind等方法实现的原理

filter用法和原理实现filter 过滤,filter()使用指定的函数测试所有元素,并创建一个包含所有通过测试的元素的新数组。 用法let arr=[2,4,6,8];let arr1=arr.filter(function(item){ return item>5})console.log(arr1) //[6,8]let arr= [ {id:1,name: "Alex", age: 18}, {id:2,name: "Teamo", age: 15}, {id:3,name: "Lily", age: 16}, {id:4,name: "Lucy", age: 17}, {id:5,name: "Tom", age: 19}]let arr1=arr.filter(function(item){ return item.age>15})console.log(arr1)//[ {id: 1, name: "Alex", age: 18},{id: 3, name: "Lily", age: 16},{id: 4, name: "Lucy", age: 17},{id: 5, name: "Tom", age: 19}]原理的实现Array.prototype.filter1 = function (fn) { if (typeof fn !== "function") { throw new TypeError(`${fn} is not a function`); } let newArr = []; for(let i=0; i< this.length; i++) { fn(this[i]) && newArr.push(this[i]); } return newArr;}let arr=[2,4,6,8];let arr1=arr.filter1(function(item){ return item>5})console.log(arr1) //[6,8]看完之后是不是so easy,其它的几个实现大同小异,建议都手写遍 ...

June 28, 2019 · 2 min · jiezi

javascript-闭包

一、定义: 常规定义: 闭包的定义: 有权利访问外部函数作用域的函数。 通俗定义: 1、函数内部包含了函数。然后内部函数可以访问外部函数的作用域。2、内部函数可以访问 父级函数的作用域。...等等等二、思考: 1、我们在日常的开发过程中会应用到 闭包么? 以之前的知识对于 闭包的理解来讲是这样的 (function(){ for(var i=0; i<10; i++) { console.log(i) } })() 或者说是这样的 var fnX = function() { var x = 123 function y() { alert(x) } y() } fnX() // 123 总结下之前的理解就是: 内部函数能访问外部函数作用域,能够保存变量不被销毁而一直存在。 三、作用: 在JavaScript中有作用域和执行环境的问题,在函数内部的变量在函数外部是无法访问的,在函数内部却可以得到全局变量。由于种种原因,我们有时候需要得到函数内部的变量,可是用常规方法是得不到的,这时我们就可以创建一个闭包,用来在外部访问这个变量。 通过将一个方法或者属性声明为私用的,可以让对象的实现细节对其他对象保密以降低对象之间的耦合程度,可以保持数据的完整性并对其修改方式加以约束,这样可以是代码更可靠,更易于调试。封装是面向对象的设计的基石。 3.1 什么是作用域3.1.1 ES5的作用域问题在 ES5 中 我们常常会说的一个概念是 局部变量 和 全局变量那么 局部变量 和 全局变量 所这个 局部 和 全局则为 作用域。这个概念其实介绍起来还是比较多虚无。 但是我记得有一本书 叫 《你不知道的JS》在这本书的 上册 作者详细的介绍了 作用域 这个概念。作用域是什么 ...

June 28, 2019 · 2 min · jiezi

深入理解JavaScript的类型转换

前言JavaScript作为一门弱类型语言,我们在每天的编写代码过程中,无时无刻不在应用着值类型转换,但是很多时候我们只是在单纯的写,并不曾停下脚步去探寻过值类型转换的内部转换规则,最近通过阅读你不知道的JavaScript中篇,对js的值类型转换进行了更加深入的学习,在此分享给大家参考学习。概念将值从一种类型转换为另一种类型通常称为类型转换,主要发生在静态语言的编译阶段;强制类型转换则发生在动态语言的运行阶段;JavaScript作为一门典型的动态弱类型语言自然而然采用的是强制类型转换(即隐式强制类型转换和显式强制类型转换);在js的强制类型转换总是返回标量基本类型值,如字符串、布尔、数字,不会返回对象和函数 var a = 42;var b = a + '';//隐式强制类型转换var c = String(a);//显式强制类型转化前情提要在阅读后面的内容之前,我们首先要明白下面几个概念,以方便对后续内容的理解 封装对象 :eg:var a = new String('abc'),a被叫做封装了基本类型的封装对象,还原一个封装对象的值,可以调用valueOf方法;基本类型的几乎所有方法并非来自本身,而是来自于封装对象的原型对象,例如下面例子 const a = 1.2;console.log(a.toFixed(0));//1基本类型数字并不存在toFixed方法,只是在访问该方法时候,js自动封装基本类型为对应的封装对象,再去访问该封装对象的原型上对应的方法,等同于下面例子 const a = 1.2;console.log(new Number(a).__proto__.toFixed());//0ToPrimitive抽象操作:该操作主要是将对象类型转换为基本类型,首先检查某个对象是否有valueOf属性,如果有则返回该对象的valueOf的值,否则调用该对象的toString属性并返回值(如果valueOf返回的不是基本类型则调用toString方法,例如数组的valueOf返回的还是数组,所有ToPrimitive会默认调用toString方法);抽象值操作ToString负责处理非字符串到字符串的强制类型转换,规则如下:1.null转换为'null',undefined转换为'undefined',其他基本类型都调用基本类型的包装对象属性toString()并返回值。const a = 123;const _a = new Number(123);console.log(String(a), _a.toString());//'123' '123'const b = true;const _b = new Boolean(true);console.log(String(b), _b.toString());//'true' 'true'2.数字的字符串化遵循通用规则,但是极小极大数字使用指数形式const a = 1.07*1000*1000*1000*1000*1000*1000*1000;console.log(String(a));//'1.07e+21'3.对于普通对象来说,除非自行定义,否则toString()返回Object.prototype.toString()的值,其他对象有自己的toString()方法则调用自己的该方法const b = {};console.log(String(b));//[object object]4.数组的默认toString()方法进行了重新定义,将所有单元字符串化以后再用‘,’连接起来const a = [1, 2, 3];console.log(String(a));//'1,2,3'5.JSON字符串化 5-1.JSON字符串化和toString的效果基本相同,只不过序列化的结果总是字符串5-2.JSON对于不安全的值(undefined,function(){},symbol)直接忽略,数组中则以null填充5-3.对象循环引用直接报错,正则表达式序列化为{}ToNumber负责处理非数字到数字的强制类型转换,规则如下:1.true转换为1,false转换为0,undefined转换为NaN,null转换为0console.log(Number(null));//0console.log(Number(undefined));//NaNconsole.log(Number(true));//1console.log(Number(false));//02.对字符串的处理遵循数字常量的相关规定/语法,处理失败时返回NaNconsole.log(Number('123'));//123console.log(Number('0b111'));//7console.log(Number('0o123'));//83console.log(Number('0x123'));//291console.log(Number('123a'));//NaNconsole.log(Number('a123'));//NaN3.对象(包括数组)会首先按照ToPrimitive抽象操作被转换为相应的基本类型值,再按照前两条规则处理;如果某个对象即不存在valueOf方法也不存在toString方法,则会产生TypeError错误(例如Object.create(null)不存在以上两种方法)const arr = [1, 2, 3];console.log(Number(arr));//NaNconsole.log(Number(arr.toString()));//NaNconst num = new Number(123);console.log(Number(num));//123console.log(Number(num.valueOf()));//123const bool = new Boolean(true);console.log(bool.valueOf());//trueconsole.log(Number(bool));//1console.log(Number(bool.valueOf()));//1const obj1 = { toString:()=>"21"}const obj2 = { valueOf:()=>"42", toString:()=>"21"}const obj3 = { a:1}console.log(Number(obj1));//21console.log(Number(obj2));//42console.log(obj3.toString());//[object Object]console.log(Number(obj3));//NaNconst obj = Object.create(null);console.log(Number(obj));//TypeError上述obj1,obj2分别调用toString和valueOf方法,obj3调用原型上的toString()方法 ...

June 28, 2019 · 3 min · jiezi

JS使用模块化实现用户名密码检测密码强弱验证验证码生成

html 页面用户名:<input type="text" id="username" name=""><br>密码:&nbsp;&nbsp;<input type="password" id="userpwd" name=""><br>密码强度:<span id="mm"></span><br>验证码:<input type="text" id="yzm" name=""> <span id="testSpan"></span><br><input type="button" id="login" value="登录" name=""/>JS代码块var module = (function() { var testSpan,msg,Slength,userpwd,userpwd,yzm; function print(msg) { alert(msg); } ;//弹出消息框 //简单的验证码 function createyzm(testSpan,Slength){ var str = "0123456789qwertyuioplkjhgfdsazxcvbnmQWERTYUIOPLKJHGFDSAZXCVBNM"; var list = str.split(""); for (i = 0; i < Slength; i++) { var index = Math.floor(Math.random() * list.length); testSpan.style.backgroundColor="#000";//验证码背景颜色 testSpan.style.color="#fff";//验证码颜色 testSpan.style.display="block"; testSpan.style.textAlign ="center"; testSpan.style.width="70px";//长度 testSpan.innerHTML += list[index]; } return testSpan.innerHTML;};function checkUserpwd(userpwd,errSpan) { var numCount = (/[0-9]/g).test(userpwd) ? 1 : 0; var lowCount = (/[a-z]/g).test(userpwd) ? 1 : 0; var uppCount = (/[A-Z]/g).test(userpwd) ? 1 : 0;//二元运算符 switch (numCount + lowCount + uppCount) { case 3: errSpan.innerHTML = "强"; break; case 2: errSpan.innerHTML = "中"; break; default: errSpan.innerHTML = "弱"; break; return true; }}; function check(username,userpwd){ var uremeber = /^[a-zA-Z0-9_-]{4,16}$/; var username=username.replace(" ",""); var userpwd=userpwd.replace(" ","");//去空格防止sql注入 if(username==""||userpwd=="") { print("用户名密码不能为空"); return false; } if(!uremeber.test(username)||!uremeber.test(userpwd)){ print("用户名密码为为4-16位但不限于(数字,字母,下划线)"); history.go(0);//刷新页面 return false; }else { //... return true; } };return { checkUserpwd: checkUserpwd,//两个参数userpwd,errSpan errspan为提示密码强弱提示性文字,接受类型是js dom对象 注:jq对象用test方法, // userpwd 为用户密码, check: check,//用户名,密码,验证码 createyzm: createyzm,//testSpan,Slength 两个参数testSpan是验证码span标签dom类型对象,Slength是验证码长度 print: print//alert弹窗 };})();var yzm=module.createyzm(document.getElementById("testSpan"),4);document.getElementById("userpwd").onblur = function(){ module.checkUserpwd(this.value,document.getElementById('mm'));}document.getElementById("login").onclick=function(){ var a= module.check(document.getElementById("username").value,document.getElementById("userpwd").value);if(a==true ){ if(document.getElementById("yzm").value==yzm){ alert("登录成功!"); }else{ alert("验证码错误,请重新输入!"); history.go(0);//刷新页面 } }}

June 28, 2019 · 1 min · jiezi

前端开发应知网站

作为一名前端开发者(所有程序员)最起码遇到bug就算不会解决也应该会搜解决问题的答案跟大家分享一下我个人积累的网站:MDN开发者文档:https://developer.mozilla.org...菜鸟教程:https://www.runoob.com/W3CSchool:http://www.w3school.com.cn/JavaScript教程网:https://zh.javascript.info/一行代码搞定bug监控:https://www.fundebug.com/?tds...阿里巴巴图标库:https://www.iconfont.cn/UI颜色布料:https://www.materialui.co/colorslogo在线制作,有很多:http://www.logofree.cn/在线开发工具:https://tool.lu/c/developer渐进式web应用程序核对表:https://developers.google.cn/...在线存放图片的地址:https://sm.ms/MintUI:https://mint-ui.github.io/#!/...ElementUI:https://element.eleme.cn/#/zh-CNiViewUI:https://www.iviewui.com/Layui:https://www.layui.com/cubeUI:https://didi.github.io/cube-u...Antd:https://ant.design/index-cnMUI:http://dev.dcloud.net.cn/mui/Animate.CSS:https://daneden.github.io/ani...ECharts:https://www.echartsjs.com/ind...HighCharts:https://www.highcharts.com.cn/蚂蚁数据可视化:http://antv.alipay.com/zh-cn/...热力图插件:https://www.patrick-wied.at/s...百度地图开放平台:https://passport.baidu.com视频监控直播的插件VLC:https://www.videolan.org/力扣JS题库:https://leetcode-cn.com/ES6入门(阮一峰大佬的):http://es6.ruanyifeng.com/babel(将ES6代码转为ES5代码):https://babeljs.io/处理时间与日期的JS库:http://momentjs.cn/Lodash:https://www.lodashjs.com/你可能不需要jQuery:http://youmightnotneedjquery....云小蜜智能机器人API:https://help.aliyun.com/produ...易万维源接口:https://www.showapi.com/api/a...短信验证码接口:https://www.mysubmail.com/sms...草料二维码生成器:https://cli.im/RAP2假数据接口:http://rap2.taobao.org/易文档接口:https://easydoc.xyz - - 感谢旅行呱大佬帮助我们丰富资源,他的CSDN主页为:https://me.csdn.net/atsoar免费接口:http://www.bejson.com/knownjs...假数据接口(测试用):http://jsonplaceholder.typico...jQuery插件库:http://www.jq22.com/search轮播图插件:https://www.swiper.com.cn/放大镜插件:http://www.elevateweb.co.uk/i...响应式瀑布流插件:http://www.jq22.com/jquery-in...小表情的emoji:https://emojipedia.org/Postman测试前端请求后端接口:https://www.getpostman.com/coding代码托管平台:https://coding.net/码云代码托管平台:https://gitee.com/github代码托管平台:https://github.com/SVN代码托管平台:https://svnbucket.com/?ADTAG=...SVN代码托管中心:http://www.svnchina.com/禅道:https://www.zentao.net/git官网:https://git-scm.com/npm官网:https://www.npmjs.com/掘金网:https://juejin.im/思否:https://segmentfault.com/知乎:https://www.zhihu.com阿里云:https://www.aliyun.com腾讯云:https://cloud.tencent.com/GitBook:https://legacy.gitbook.com/@l...妙味课堂:https://miaov.com/慕课网:https://www.imooc.com/html中文网:https://www.html.cn/hCoder:http://www.hcoder.net/扣丁学堂:http://www.codingke.com/React官网:https://reactjs.org/Redux官网:https://react-redux.js.org/React Router:https://reacttraining.com/rea...Vue官网:https://cn.vuejs.org/NodeJS官网:http://nodejs.cn/uni-app:https://uniapp.dcloud.io/微信开发者平台:https://developers.weixin.qq....DvaJS:https://dvajs.com/jQuery官网:https://jquery.com/jQuery API中文文档:http://jquery.cuishifeng.cn/ZeptoJS官网:https://zeptojs.com/cheerioJS安装地址:https://www.npmjs.com/package...RequireJS官网:https://requirejs.org/Sass官网:https://sass-lang.com/Less官网:http://lesscss.org/Bootstrap官网:https://www.bootcss.com/VScode快捷键介绍:https://www.cnblogs.com/bindo...Socket通信:https://socket.io/JSONPlaceholder:http://jsonplaceholder.typico...web开发互助网:http://hz.uyi2.com/

June 28, 2019 · 1 min · jiezi

offsetLeftoffsetTop与getClientRect0xgetClientRect0y-关系

getClientRect是元素的绝对位置,绝对指的是相对于显示器视口的决定定位。offsetLeft的理解方式同position:absolute,相对的是上一个不为static的元素,而不是body或者html之类的 如果页面上只有一个元素,则两种值会相同,会造成概念混淆

June 28, 2019 · 1 min · jiezi

区块链喧嚣不止ETM何以成为行业清流

从没有哪个行业像区块链这般,不惮以超速来强化人们的快感,在争分夺秒中展现出时代的失重感。 随着今年4月牛市迹象逐渐显明,几番大涨小跌勾得人心痒。截至发稿前,比特币最高已触13900点,再次登上热搜,身边的炒币玩家也无不期待明年比特币减产带来的财富虹吸。 币价涨得像踩了油门,高涨的行情刺激着投资者神经的同时,数字货币编织出的暴富梦也使区块链越来越吸引注意力,从极客到科幻爱好者,从自由主义者到投机者,人们无不希望在这片炙手可热的土地上淘到金。 风口大敞的区块链入口,大大小小的项目在浪潮中奋力涌动,有的从无人问津到一夜爆红,有的星星之火依然等待着绽放之时照亮夜空。 将硬核进行到底En-Tan-Mo,这匹名不见经传的黑马正从夜幕冲出。 一直以来深耕于技术,更因执着钻研的气质吸引两位诺奖得主加入,它成为首个提出并解决SHD完备性的公链项目。基于纳什均衡和价值传递理论,ETM的科学家们将PoW和PoS改进并结合,创造性地以UPoS共识机制突破算力证明与权益证明的弊端并进行改进。既给予矿工参与生产的更大可能性,又赋予每一位持有ETM的用户以参与投票的机会。 团队对技术的打磨从未停止,核心代码阶段性梳理、数据库结构优化、测试矿机 GUI 客户端、优化侧链数据库结构、矿机一键部署脚本改进、研发ETM 钱包移动端... 公开透明地推动技术演进,En-Tan-Mo的社区认同并非空穴来风。 硬核式输出 筑起用户认同人类社会的数据发生爆炸式的增长,但指数级增长的信息早已超出人类大脑的认知阈值。井喷的信息或许起初卷起泡沫渣滓充斥水面,但几番潮涨潮落之后留下的终归是那些有价值的东西。 所以在信息爆炸与过剩的当下,如何获取用户实属不多的注意力? En-Tan-Mo的选择是:提供有价值的内容。 为社区用户提供扎实的专业化的信息,正因为人们在技术的变化中所能够感觉到的是具象的世界变动,缺乏引起共情的元素。而将文字作为En-Tan-Mo的符号,内蕴团队的世界观、价值观,以理念与信仰唤起用户的认同。 技术的改变本身不是最终目的,技术带来的思考才是我们对这个可塑世界作出的延展。所以En-Tan-Mo在荒地上逡巡探索,在脑海中展开无际想象,在白纸上涂写构思。他们必然需要说些什么,才能记录那些当下被改变的轨迹。 一年前发布的En-Tan-Mo白皮书不局限技术层面,从哲学、数学、经济学等多个学术维度对项目进行阐述。时隔一年,今年六月发布的项目黄皮书除着眼于技术解读外,还对中本聪的理念作出解读,赋权与去中心化的实现并不是一场未竟之梦。 而在各种区块链项目烟花式地以各种玩法招徕用户,令人目眩神迷的时候,En-Tan-Mo特立独行地在社区推出精进课堂、日拱一卒等栏目为用户传布行业知识以及热点资讯,将【ETM科学院】作为一个深耕区块链行业讯息的空间,以学理为原材料不断输出内容。 就是这样,En-Tan-Mo拥有与其他项目方不同的气质。或许如此行为确实与四处高喊着“梭哈,不要怂”的圈子显得格格不入,但是事实是,正是因为在价值传播上的纯粹的坚持,En-Tan-Mo获得了用户的认同。 硬核式发展 扎根用户初心未变架构在区块链上的比特币刚走过风雨十年。有人狂欢追逐,也有人低调前行。距离En-Tan-Mo登陆交易所已过去17天,团队虚心接受外界的赞美,也咽下所有的冷嘲与诋毁,但是他们从来没有也不想改变出发时的初衷。 像是Forrest Gump说的,“丹中尉不想被人叫做残废,他知道我不想被叫做傻子”。执着是一种天赋,有的人执着于登上热搜以流量加身,有的人执着于以技术吸引用户。En-Tan-Mo的执着很纯粹——打磨技术,回馈用户。继承前人志向,En-Tan-Mo崇尚的自由与去中心化世界中仍然映照着面向大众,回归大众的初心。 我们总是听见币民自我调侃为“韭菜”,将许多项目方的市场行为看作是“割韭菜”。市场主体的行为以一句“一个愿涨,一个愿割”草草作了交代。作为区块链行业的市场主体,En-Tan-Mo固然需要通过与大家以及交易所的互动获得相应盈利,但是盈利并非En-Tan-Mo的最终目的。 作为中本聪去中心化精神的追随者,我们自2017年问世,便循其航行轨迹寻找出路。 中本聪寻找一片无所属的去中心化海域,En-Tan-Mo继承其梦想建设一个远离寡头的去中心化世界,用户作为主角决定世界未来的发展路径,作为生态架构者的团队未来将逐步退出决策过程。 无意以过多喧哗吸引用户关注,En-Tan-Mo不疾不徐探索区块链的未来。 **为何成为行业里一支清流?En-Tan-Mo给出了答案。或许行业喧嚣,但En-Tan-Mo热忱不变。**

June 28, 2019 · 1 min · jiezi

vue-filter-完美时间日期格式

<template> <div>{{msg | compFilter('yyyy-MM-dd hh:mm') }}</div></template> <script>export default { data() { return { msg: new Date() // msg: 10, }},filters: { compFilter: function(value, format) { let o = { "M+": value.getMonth() + 1,![图片描述][1] "d+": value.getDate(), "h+": value.getHours(), "m+": value.getMinutes(), "s+": value.getSeconds(), } if(/(y+)/.test(format)){ format = format.replace(RegExp.$1, (value.getFullYear() + "").substr(4-RegExp.$1.length)); for(let k in o) { if(new RegExp(`(${k})`).test(format)){ format = format.replace(RegExp.$1, (RegExp.$1.length == 1)?(o[k]):(("00" + o[k]).substr((""+o[k]).length))) } } return format; } }},}</script> ...

June 28, 2019 · 1 min · jiezi

H5中video标签那些属性和方法

前言最近在写一个自定义播放器, 写之前我们肯定要把播放器的属性和方法全部过一遍,知彼知己,方能百战不殆嘛...后面会把自己写的播放器和踩过的一些坑也上传上来 video标签行内属性src:视频的URLposter:视频封面,没有播放时显示的图片preload:预加载autoplay:自动播放loop:循环播放controls:浏览器自带的控制条width:视频宽度height:视频高度webkit-playsinline="true" IOS下防止全屏播放playsinline="true" 同上x-webkit-airplay="true" 支持ios的AirPlay功能x5-video-player-type="h5" 启用同层H5播放器x5-video-player-fullscreen="true" 全屏设置x5-video-orientation="portraint" 竖屏style="object-fit:fill" 封面铺满muted="true" 静音播放应该还有一些...不过暂时没用到, 可以去查MDN文档video对象的属性和方法1.错误状态 $video.error; //null:正常 $video.error.code; //1.用户终止 2.网络错误 3.解码错误 4.URL无效 2.网络状态属性(有些比较常用) $video.currentSrc; //返回当前资源的URL $video.src = value; //返回或设置当前资源的URL $video.canPlayType(type); //是否能播放某种格式的资源 $video.networkState; //0.此元素未初始化 1.正常但没有使用网络 2.正在下载数据 3.没有找到资源 $video.load(); //重新加载src指定的资源 $video.buffered; //返回已缓冲区域,$video.buffered.end(0)拿到最后一刻的数据 $video.preload; //none:不预载 metadata:预载资源信息 auto: 3.准备状态 $video.readyState; //1:HAVE_NOTHING 2:HAVE_METADATA 3.HAVE_CURRENT_DATA 4.HAVE_FUTURE_DATA 5.HAVE_ENOUGH_DATA $video.seeking; //是否正在seeking 4.播放状态(常用) $video.currentTime = value; //当前播放的位置,赋值可改变位置 $video.duration; //当前资源长度 流返回无限 $video.paused; //是否暂停 $video.defaultPlaybackRate = value;//默认的回放速度,可以设置 $video.playbackRate = value;//当前播放速度,设置后马上改变 $video.seekable; //返回可以seek的区域 $video.ended; //是否结束 $video.autoPlay; //是否自动播放 $video.loop; //是否循环播放 $video.play(); //播放 $video.pause(); //暂停 5.控制 ...

June 27, 2019 · 1 min · jiezi

iOS-App渠道统计跟踪方法

说起 iOS 的渠道统计,不少人会想到苹果官方的 App 分析功能(iTunes Connect),但实际操作中我们会发现,这个服务的统计维度还不够全面,许多广告主和运营人员更关心的是各个推广渠道实际带来的安装量、注册量等数据,毕竟这对渠道引流的分析价值更大。iOS的“渠道”通常是指那些在其它 App 或者网页内部,提供到达 App Store 的链接的页面。因此,在 iOS 中追踪发行渠道,主要是追踪进入 App Store 相关页面的渠道信息。 从技术角度来看,也就是在用户首次下载时不仅要获取下载来源,还要实现参数传递,简单来说,就是用户第一次下载后,我能得知后续的注册、活跃、付费等操作行为。或者在此基础上,实现场景还原,帮助用户在首次打开 App 后直接跳转进指定页面,而不是首页。 方案一:苹果官方自带的统计工具 iTunes Connect 登录 iTunes Connect ,在“App 分析”中,能很方便的查看 App 的展示次数、购买量等基础数据,但无法获取更加详细的安装量、注册量等运营数据。 当然,往往 App 推广的渠道会有很多同时进行,怎么对多个渠道的来源做分析呢?同样在“App分析”的“来源”中点击“营销活动”,右上角有个“生成营销活动链接”,进入后就能自定义给每个渠道生成对应的唯一标识。 这种方法虽然可以追踪到多个渠道的来源,但存在以下几个问题: 只有当营销活动启动后超过一天时间(最长72个小时)后才能显示相关数据;至少有 5 个 App 购买量归因于此营销活动时,营销活动才会在“App 分析”中显示;统计的维度不完整,仅限“展示次数”、“App 购买量”、“销售额”、“App 使用次数”四个;iOS 8.0 及以上版本的用户可以选择是否将自己的应用使用情况的数据发送给Apple。方案二:使用 SFSafariViewController 传递参数SFSafariViewController 是 iOS 9.0 出现的,可以通过 Safari 对应的 cookier 传递参数,跨App与Safari共享数据。但是 openurl 失败率还是很高,并且有系统版本、浏览器等限制,比如微信等第三方 App 的内置浏览器就不能很好实现。 方案三:通过 IDFA 进行追踪,比如 Google Analytics常用的比如谷歌官方的 Google Analytics,它的获取原理就是通过获取设备的 IDFA ,来作为唯一标示符号,然后根据你的渠道来源提供数据,通过比对的方式进行渠道定位。弊端在于,用户重置系统,或者关闭广告跟踪的话,这种方法就会失效。 ...

June 27, 2019 · 1 min · jiezi

select2-和-ajax的坑

select2,一款带多选功能,样式更加好看的select插件。 下方记录坑,前方高能. 要用ajax发请求并且为select2赋初始值 $.ajax({ url : _ctx+"/basInfo/listPsinfoData", data : "page=1&rows=9999&flag=1", type : "post", async : false, success : function(msg) { $("#" + PreSeleltName + "PSCODES").empty(); var pscodeList = []; var pscodeString = ""; var tempList = []; var data = msg.rows; for ( var i in data) { var temp = data[i]; var tempPscode = temp.PSCODE; var tempPsname = temp.PSNAME; if(tempPscode && tempPsname){ tempList.push({id :temp.PSCODE,text :temp.PSNAME}); } } //初始化select2 企业 并且 赋值到vmData.data.PSCODELIST $("#" + PreSeleltName + "PSCODES").select2({ data:tempList, placeholder:'选择或搜索企业',//默认文字提示 multiple: true,//多选 allowClear: true }).change(function(){ pscodeList = $("#" + PreSeleltName + "PSCODES").val(); for(var i in pscodeList){ var pscode = pscodeList[i]; if(i == 0){ pscodeString = pscode; }else{ pscodeString = pscodeString + ","+ pscode; } } Vue.set(vmData.data, 'PSCODELIST', pscodeString); }); }, });这样select2下拉列表就有了对应的值 ...

June 27, 2019 · 1 min · jiezi

为什么网站的cookie有时候获取不到

工作中有好多同事问我,那个谁,为什么我用网上封装的获取cookie的方法却获取不到自己网站上的cookie呢? 这个问题,我们还要从document.cookie说起(其实网上封装的获取cookie的方法里面也是用的这个方法),MDN上给的文档:注意,这里给出的解释是获取所有可从此位置访问到的cookie; 不着急,咱们继续往下看;这是文档里给出的属性值; ;path=path (例如 '/', '/mydir') 如果没有定义,默认为当前文档位置的路径。;domain=domain (例如 'example.com', 'subdomain.example.com') 如果没有定义,默认为当前文档位置的路径的域名部分。与早期规范相反的是,在域名前面加 . 符将会被忽视,因为浏览器也许会拒绝设置这样的cookie。如果指定了一个域,那么子域也包含在内。;max-age=max-age-in-seconds (例如一年为606024*365);expires=date-in-GMTString-format 如果没有定义,cookie会在对话结束时过期;secure (cookie只通过https协议传输)其实造成取不到值得主要原因就是path这个属性,这里的path属性是指你可以从xxx.xxx.com/xxx/x中访问到cookie(当时是在这个页面设置的cookie),但在xxx.xxx.com这个目录下是访问不到此cookie的; 这就相当于你在A店里定了一盒曲奇饼干,但你去B店拿,显然是拿不到的。 在浏览器中也可以很方便很直观的看到区别: 但是这里也有一个规则,就是子文件夹下的页面可以访问上级页面存下的cookie,但父级文件夹的页面访问不到子文件夹下的页面创建的cookie;所以,通常我们在设置cookie的时候,可以统一把path设置为/;下面附cookie的CRUD代码: var cookie = { /** * 设置cookie * @param name cookie的名称 * @param value cookie的值 * @param day cookie的过期时间 */ setCookie: function (name, value, day) { if (day !== 0) { //当设置的时间等于0时,不设置expires属性,cookie在浏览器关闭后删除 var expires = day * 24 * 60 * 60 * 1000; var date = new Date(+new Date() + expires); document.cookie = name + "=" + escape(value) + ";expires=" + date.toUTCString()+";path=/"; } else { document.cookie = name + "=" + escape(value)+";path=/"; } }, /** * 获取对应名称的cookie * @param name cookie的名称 * @returns {null} 不存在时,返回null */ getCookie: function (name) { var arr; var reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)"); if (arr = document.cookie.match(reg)) return unescape(arr[2]); else return null; }, /** * 删除cookie * @param name cookie的名称 */ delCookie: function (name) { this.setCookie(name, ' ', -1); } }

June 27, 2019 · 1 min · jiezi

使用js-FormData传文件流传json重点

先介绍js的FormData,FormData是XMLHttpRequest Level 2新增的一个接口,利用FormData对象,我们可以通过JavaScript用一些键值对来模拟一系列表单控件,我们还可以使用ajax方法来异步的提交这个"表单".使用FormData的最大优点就是我们可以异步上传一个二进制文件.这里说下FormData的append方法, 给当前FormData对象添加一个键/值对(append)void append(DOMString name, Blob value, optional DOMString filename);void append(DOMString name, DOMString value);参数值name字段名称. value字段值.可以是,或者一个字符串,如果全都不是,则该值会被自动转换成字符串. filename(可选) 指定文件的文件名,当value参数被指定为一个Blob对象或者一个File 接口提供有关文件的信息,并允许网页中的 JavaScript 访问其内容。")对象时,该文件名会被发送到服务器上,对于Blob对象来说,这个值默认为"blob". 这里要注意下value字段,如果你要填入的是一个对象,会将它转换成字符串,也就是最后传给后台的都是[object object],这样后台当然是无法解析的。下边举个例子,大家就明白了 好了,请上我们的两位同学,小明和胖虎,你们就不用发言了,我会以json的形式介绍你们的情况和个人癖好,请坐。 var json=[ {'name':'小明','age':15,'skills':['抽烟','喝酒','烫头'],'family':{'father':'大明','mohter':'小红'}}, {'name':'胖虎','age':17,'skills':['打架','打架','还是打架'],'family':{'father':'佐藤','mohter':'爱田'}}, ]首先我们先试一下,把小明的family对象传给后台。 var data=new FormData() data.append('family',json[0].family) $.ajax({ url:'demo.php', type: "Post", dataType: "json", cache: false,//上传文件无需缓存 processData: false,//用于对data参数进行序列化处理 这里必须false contentType: false, //必须 data:data, success:function (res) { console.log(res); }, error:function (error) { console.log(error); } })结果:被解析成了object object,有人该说了,你把它用JSON.stringify序列化之后不就行了,然后后端配合,再解码成json,对,这样确实行,但不要忘了,咱们还是需要传文件流的,文件流被序列化之后会被转化成一个空对象,这样后台就无法识别。由于时间原因,这里就不演示反面案例了。这里我们要用两个语法1.a['b']等于a.b2.c[0]取得是c数组的第一项正确方法: var data=new FormData()for(var i=0,len=json.length;i<len;i++){ data.append('json['+i+'][name]',json[i].name) data.append('json['+i+'][age]',json[i].age) data.append('json['+i+'][family][father]',json[i].family.father) data.append('json['+i+'][family][mother]',json[i].family.mohter) for(var j=0,len2=json[i].skills.length;j<len2;j++){ data.append('skills['+i+']['+j+']',json[i].skills[j]) } } $.ajax({ url:'demo.php', type: "Post", dataType: "json", cache: false,//上传文件无需缓存 processData: false,//用于对data参数进行序列化处理 这里必须false contentType: false, //必须 data:data, success:function (res) { console.log(res); }, error:function (error) { console.log(error); } })之后,我们再给小明和胖虎每人上传一张个人写真照(利用inputfile,文件流)这里我们利用input上传时的file对象,附上代码: ...

June 27, 2019 · 1 min · jiezi

数据可视化初学者指南定义示例和学习资源

数据可视化是信息和数据的图形表示。通过使用图表,图形和地图等可视元素,数据可视化工具提供了一种可访问的方式来查看和理解数据中的趋势,异常值和模式。在大数据领域,数据可视化工具和技术对于分析大量信息和制定数据驱动决策至关重要。 轻松地给各类图添加或输入数据Visual Paradigm Online 提供了一个非常方便的图表编辑编辑器。只需转到图表制作者,即可从模板创建条形图。它将弹出一个数据表供您输入数据和类别。输入您的数据,您的更改将立即显示在表格旁边的条形图上。 自定义图表颜色和字体在条形图中为条形选择您喜欢的颜色。您还可以调整图表大小或缩放以适合任何维度。所有这一切都可以通过几次点击完成。 轻松缩放或调整条形图的大小想要将条形图添加到报告或演示文稿中吗?您可以将图表调整大小或缩放到任何尺寸,适合任何页面或幻灯片。只需拖动图表的边缘或角落即可调整其大小。 与您的同事协作Visual Paradigm Online是一个在线图表创建者。只需创建一个在线工作区并开始与同事一起创建图表。您的所有作品都保存在云端,因此您可以随时随地访问它们。 更多图表和图表您可以使用Visual Paradigm Online创建各种图表。点击下面的图表了解更多详情。 柱形图 折线图 饼形图 甜甜圈图 条形图 面积图 散点图 气泡图 雷达图 画报图 金字塔图表 漏斗图 仪表图 径向图 玫瑰图 热图 树地图

June 27, 2019 · 1 min · jiezi

vue中给window移除事件监听失败的问题

在mounted中给vue添加了一个事件监听,然后再beforedestory中移除事件监听,发现移除事件监听失败后来发现想要移除window的addEventListener,需要把后面的function挂在到this上 mounted () { window.addEventListener('resize', this.listenResize) }, beforeDestroy () { window.removeEventListener('resize', this.listenResize) }listenResize方法我定义在methods中具体请参考baoleilei6的文章

June 27, 2019 · 1 min · jiezi

优雅的防止用户重复点击某个按钮

前言:想必前端小伙伴都遇到过一个问题:点击某个按钮时如果点击的比较快,可能会触发多次。如果查询操作影响还不大,如果是提交操作,那就会有问题了。接下来为大家介绍几种防止重复点击的小妙招。基础:给请求添加loading效果。这个是网站必备的装逼特效,既能告诉用户系统已经在帮用户搞事情了,又可以防止用户在此期间做其他操作。进阶(方法1): 使用防抖。 防抖: 在一定时间内,动作只会执行一次(大家可以使用loadsh的debounce方法,也可以自己写)。举个例子:我在网上买了很多东西,今天很多快递都会到,时不时的就会有快递小哥的电话,我不想来回去取快递,就每隔1个小时取一次,如果1个小时内没有快递,就不下楼拿快递了。 建议:第一次点击立即执行,后面的点击每隔一段时间执行一次。(debounce的leading设置为true) 进阶(方法2):变量控制。 如果按钮和事件处理在一个组件中,那么我们可以使用变量来控制,以react为例: 建议使用防抖的方式,写法简单,可维护性高。如果您还有其他比较好的方法,欢迎留言。 过几天会写防抖的文章,欢迎关注。

June 27, 2019 · 1 min · jiezi

前端培训中级阶段5-jQuery的概念与基本使用20190711期

前端最基础的就是 HTML+CSS+Javascript。掌握了这三门技术就算入门,但也仅仅是入门,现在前端开发的定义已经远远不止这些。前端小课堂(HTML/CSS/JS),本着提升技术水平,打牢基础知识的中心思想,我们开课啦(每周四)。 前面我们已经基本掌握常规的语法语义,以及基本的使用方法。接下来我们讲深入进去了解其中内在的原理。也了解 DOM、BOM,但是因为规范是一在变的,有没有什么类库可以方便操作这些呢?进入我们今天的主题jQuery jQuery这东西出来很久了,一般来说都用过。提供一个速查地址 jQuery 简介jQuery 设计的宗旨是“write Less,Do More”,即倡导写更少的代码,做更多的事情。jQuery 是一个跨浏览器(兼容所有常见浏览器,包括IE6)的工具库。提供了元素选取、元素操作、CSS操作、事件处理、动画、AJAX等功能。 jQuery 的特点链式操作(很优秀)高效、灵活的选择器(id、class、tag、伪元素、attr、层级)插件机制兼容主浏览器,提供了统一的功能接口jQuery 插件机制jQuery.fn.extend(object) 对应 $('div'). 的操作。 jQuery.fn.extend({ check: function() { return this.each(function() { this.checked = true; }); }, uncheck: function() { return this.each(function() { this.checked = false; }); }});$("input[type=checkbox]").check();$("input[type=radio]").uncheck();jQuery.extend(object) 对应 $. 的操作。 jQuery.extend({ min: function(a, b) { return a < b ? a : b; }, max: function(a, b) { return a > b ? a : b; }});jQuery.min(2,3); // => 2jQuery.max(4,5); // => 5jQuery.extend([deep], target, object1, [objectN])用一个或多个其他对象来扩展一个对象,返回被扩展的对象。如果不指定target,则给jQuery命名空间本身进行扩展。这有助于插件作者为jQuery增加新方法。 如果第一个参数设置为true,则jQuery返回一个深层次的副本,递归地复制找到的任何对象。否则的话,副本会与原对象共享结构。 未定义的属性将不会被复制,然而从对象的原型继承的属性将会被复制。 ...

June 27, 2019 · 1 min · jiezi

jQuery源码解析之animate上

前言:需要先看 jQuery源码解析之$.queue()、$.dequeue()和jQuery.Callbacks() 一、举例divA 的宽度先变成 500px,再变成 300px,最后变成 1000px: <script src="jQuery.js"></script> <div id="A" style="width:100px;height:50px;background-color: deeppink">这是A</div><script> let A = document.querySelector('#A'); //在异步调用中,进行同步调用 //动画是异步的 A.onclick = function() { //就是连续调用animation.add() $('#A').animate({ 'width': '500' }).animate({ 'width': '300' }).animate({ 'width': '1000' }); };</script>二、$().animate()作用:通过 CSS 样式将元素从一个状态改变为另一个状态 源码: //之前有说过: jQuery.fn.extend() 是$()的方法 jQuery.fn.extend( { //源码8062行 //{'width': '500'} animate: function( prop, speed, easing, callback ) { //是否是空对象,false var empty = jQuery.isEmptyObject( prop ), // optall={ // complete:function(){jQuery.dequeue()}, // old:false, // duration: 400, // easing: undefined, // queue:"fx", // } //undefined undefined undefined optall = jQuery.speed( speed, easing, callback ), doAnimation = function() { // Operate on a copy of prop so per-property easing won't be lost //Animation 方法执行单个动画的封装 //doAnimation的本质是执行Animation方法 //this:目标元素 //{'width': '500'} //optall={xxx} var anim = Animation( this, jQuery.extend( {}, prop ), optall ); // Empty animations, or finishing resolves immediately //finish是数据缓存的一个全局变量 //如果为true,立即终止动画 if ( empty || dataPriv.get( this, "finish" ) ) { anim.stop( true ); } }; //注意这个 //自身的.finish=自身 doAnimation.finish = doAnimation; return empty || optall.queue === false ? this.each( doAnimation ) : //一般走这里 //通过 queue 调度动画之间的衔接 //optall.queue:"fx" //doAnimation:function(){} this.queue( optall.queue, doAnimation ); }, })解析:(1)jQuery.speed()作用:初始化动画对象的属性 ...

June 27, 2019 · 3 min · jiezi

webpack-vuecli3-压缩图片

webpack vue-cli3 压缩图片yarn add image-webpack-loaderconfig.module.rules.push({ test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, use:[{ loader: 'image-webpack-loader' options: {bypassOnDebug: true} }]})

June 26, 2019 · 1 min · jiezi

关于js返回上一页的实现方法

下面是常用代码: <a href="<a href="javascript :history.back(-1)">返回上一页</a>或 <a href="javascript :;" onClick="javascript :history.back(-1);">返回上一页</a>如果是用按钮做的话就是: <input type="button" name="Submit" onclick="javascript:history.back(-1);" value="返回上一页">用图片做的话就是: <a href="javascript :;" onClick="javascript :history.back(-1);"><img src="图片路径" border="0" title="返回上一页"></a>[color=#FF0000]几秒钟后[/color]自动返回上一页代码:(加入两个head间,3000表示3秒) <SCRIPT language=javascript>function go(){window.history.go(-1);}setTimeout("go()",3000);</SCRIPT>

June 26, 2019 · 1 min · jiezi

怎么修改inputtextarea元素中的placeholder属性样式

input::-webkit-input-placeholder{} /* 使用webkit内核的浏览器 */input:-moz-placeholder{} /* Firefox版本4-18 */input::-moz-placeholder{} /* Firefox版本19+ */input:-ms-input-placeholder{} /* IE浏览器 */

June 26, 2019 · 1 min · jiezi

这儿有20道大厂面试题等你查收

今年来,各大公司都缩减了HC,甚至是采取了“裁员”措施,在这样的大环境之下,想要获得一份更好的工作,必然需要付出更多的努力。 本文挑选了20到大厂面试题,大家在阅读时,建议不要先看我的答案,而是自己先思考一番。尽管,本文所有的答案,都是我在翻阅各种资料,思考并验证之后,才给出的。但因水平有限,本人的答案未必是最优的,如果您有更好的答案,欢迎给我留言。 本文篇幅较长,希望小伙伴们能够坚持读完,如果想加入交流群,可以通过文末的公众号添加我为好友。 1. new的实现原理是什么?new 的实现原理: 创建一个空对象,构造函数中的this指向这个空对象这个新对象被执行 [[原型]] 连接执行构造函数方法,属性和方法被添加到this引用的对象中如果构造函数中没有返回其它对象,那么返回this,即创建的这个的新对象,否则,返回构造函数中返回的对象。function _new() { let target = {}; //创建的新对象 //第一个参数是构造函数 let [constructor, ...args] = [...arguments]; //执行[[原型]]连接;target 是 constructor 的实例 target.__proto__ = constructor.prototype; //执行构造函数,将属性或方法添加到创建的空对象上 let result = constructor.apply(target, args); if (result && (typeof (result) == "object" || typeof (result) == "function")) { //如果构造函数执行的结构返回的是一个对象,那么返回这个对象 return result; } //如果构造函数返回的不是一个对象,返回创建的新对象 return target;}2. 如何正确判断this的指向?如果用一句话说明 this 的指向,那么即是: 谁调用它,this 就指向谁。 但是仅通过这句话,我们很多时候并不能准确判断 this 的指向。因此我们需要借助一些规则去帮助自己: this 的指向可以按照以下顺序判断: 全局环境中的 this浏览器环境:无论是否在严格模式下,在全局执行环境中(在任何函数体外部)this 都指向全局对象 window; ...

June 26, 2019 · 11 min · jiezi

前端小知识10点2019625

前言:这里记录我工作、学习中值得注意的小知识点,希望对你有所帮助。 1、 moment.js将某年某周转为具体日期 举例:将2019年第二周转为具体日期 <script src="moment.js"></script><script> const year=2019 const week=2 const start = moment() //年 .year(year) //周 .week(week) //周一 .isoWeekday(1) //日期格式 .format('M.D'); const end = moment() .year(year) .week(week) .isoWeekday(7) .format('M.D'); //2019第2周 //(1.7-1.13) console.log(`${year}第${week}周\n(${start}-${end})`) </script>(1)关于ISO 8601时间标准对周的定义,请参考:ISO 8601中周数的处理及 Joda-Time 的使用 (2)moment.js将某年某周转化为具体日期的方法,请参考:http://momentjs.cn/docs/#/get-set/iso-weekday/ 2、IE11导出excel表格和图片(兼容性) 导出 excel: const fileData = ['' + ('<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-mic' + 'rosoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40"><head><meta cha' + 'rset="UTF-8"><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:Exce' + 'lWorksheet><x:Name>{worksheet}</x:Name><x:WorksheetOptions><x:DisplayGridlines/>' + '</x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></' + 'xml><![endif]--></head><body>') + a.outerHTML + '</body></html>'];const blobObject = new Blob(fileData);window.navigator.msSaveOrOpenBlob(blobObject, `${tableTitle}.xls`);说明:a.outerHTML是<table id='a'>的outerHTML ...

June 26, 2019 · 2 min · jiezi

JavaScript-数据类型二

Object 类型ECMAScript中的对象就是一组数据和功能的集合。 创建对象const o = new Object();const o = new Object; // 有效,但不推荐省略圆括号const o = {};实例属性和方法:constructor: 构造函数。hasOwnProperty(propertyName): 检查 propertyName (传入的属性)在当前对象实例中(不是实例原型中)是否存在。isPrototypeOf(object): 用于检查传入的对象是否是当前对象的原型。propertyIsEnumerable(propertyName): 检查 propertyName (传入的属性)是否能够使用 for-in 语句枚举。toLocaleString(): 返回对象的字符串表示,该字符串与执行环境的地区对应。toString(): 返回对象的字符串表示。valueOf(): 返回对象的字符串、数值或布尔值表示。通常与toString()返回值相同。const o = new Object();console.log(o.toLocaleString()); // "[object Object]"console.log(o.toString()); // "[object Object]"console.log(o.valueOf()); // "{}"Symbol 类型表示独一无二的值。是一种基本数据类型。每个从Symbol()返回的symbol值都是唯一的。一个symbol值能作为对象属性的标识符;这是该数据类型仅有的目的。它不支持语法:new Symbol()。 围绕原始数据类型创建一个显式包装器对象从 ECMAScript 6 开始不再被支持。 然而,现有的原始包装器对象,如 new Boolean、new String以及new Number因为遗留原因仍可被创建。 创建Symbol([description])description: 可选的字符串。symbol的描述,可用于调试(控制台显示、转为字符串等)但不能访问symbol本身。如果 Symbol 的参数是一个对象,就会调用该对象的toString方法,将其转为字符串,然后才生成一个 Symbol 值。 var sym1 = Symbol();var sym2 = Symbol('foo');var sym3 = Symbol('foo');typeof sym1 // "symbol"sym1 // Symbol()sym2 // Symbol('foo')sym3 // Symbol('foo')sym1.toString() // "Symbol()"sym2.toString() // "Symbol(foo)"sym3.toString() // "Symbol(foo)"sym2 === sym3 // falsevar sym = new Symbol(); // TypeError// 创建一个Symbol包装器对象var sym = Symbol("foo");typeof sym; // "symbol"var symObj = Object(sym);typeof symObj; // "object"// 运算`your symbol is ${sym}`// TypeError: can't convert symbol to stringBoolean(sym) // trueNumber(sym) // TypeErrorSymbol.for([description])Symbol.for()与Symbol()这两种写法,都会生成新的 Symbol。它们的区别是,前者会被登记在全局环境中供搜索,后者不会。Symbol.for()不会每次调用就返回一个新的 Symbol 类型的值,而是会先检查给定的key是否已经存在,如果不存在才会新建一个值。 ...

June 26, 2019 · 1 min · jiezi

思考-鼠标拖拽mousemove和移动端touchmove问题

需求移动实现手指触摸移动物体PC端实现鼠标拖拽物体实现移动端 通过touchstart和touchmove事件实现1、touchstart时记录手指按下的位置 x=event.touch[0].pageX, y=event.touch[0].pageY,为A(为了方便描述)2、移动时touchmove中获取移动过程中的位置,为B3、计算此次移动的距离C(正或者负),4、将移动物体的绝对位置更新:原始位置加上移动距离,5、更新A的值。进入下一次移动事件 管理端1、mousedown时记录手指按下的位置 x=event.clientX, y=event.clientY,为A(为了方便描述)2、移动时touchmove中获取移动过程中的位置,为B3、计算此次移动的距离C(正或者负),4、将移动物体的绝对位置更新:原始位置加上移动距离,5、更新A的值。进入下一次移动事件

June 25, 2019 · 1 min · jiezi

思考-移动端绝对定位在不同设备适配问题

需求:需要展示的数据已在数据库设置好,并且是以大屏幕为准,现在需要在不同设备上显示出来实现:所有物体都采用绝对定位,根据实际屏幕与数据库设置的屏幕尺寸比例,对数据进行缩放背景 居中铺满 background-position: center center;background-size: cover;中间内容 水平和垂直居中 width:500px;height:300px; // 假设宽高是这么多 position:absolute;top:50%,left:50%;transition:translate(-50% -50%);canvas画布上的图形或图片 canvas上面不同于其他dom,画布宽高不能通过样式设置,否则容易模糊,所以宽高通过计算后的宽高设置。 1、canvas上画的图形: canvas宽高缩放后的值显示,画布上的元素的每个坐标缩放后画上去。 2、canvas显示图片(迷宫) canvas的宽高,不能缩放,必须整张图的宽高来显示,不然图片会被剪切掉,所以只能将整个canvas渲染完成后使用样式的scale缩放。引申出的问题是,迷宫中的“小人”运动时的对出口的判断,采用移动的当前位置是否超过迷宫的宽高,这时候的宽高也就不能使用缩放后的值,虽然看起来迷宫变小了,但其实里面的坐标是没有变的。 交互中的复杂问题 1、拖动物体摆放位置 物体的宽高,起点位置都已计算 2、拖动物体过程中 移动过程中移动距离需要缩放; 3、元素目标位置是否为预设的位置判断 预设位置已进行计算

June 25, 2019 · 1 min · jiezi

DOM和CSS渲染过程摘抄021

DOM和CSS渲染过程DOM<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title></head><body> </body></html>一个简单的html页面如上所示。 DOM有两个概念: 解析渲染DOM解析DOM解析:就是把你所写的各种html标签,生成一个DOM TREE,可以认为就是生成了一个最原始的页面,一点样式都没有,毫无CSS修饰。 DOM渲染:浏览器会把本身默认的样式+用户自己写得样式整合到一起,形成一个CSS TREE,而DOM渲染就是指DOM TREE 和 CSS TREE 结合到一起,生成一个Render TREE,呈现出一个带有样式的页面。 1)浏览器会解析三个东西: 一个是HTML/SVG/XHTML,事实上,Webkit有三个C++的类对应这三类文档。解析这三种文件会产生一个DOM Tree。CSS,解析CSS会产生CSS规则树。Javascript,脚本,主要是通过DOM API和CSSOM API来操作DOM Tree和CSS Rule Tree.2)解析完成后,浏览器引擎会通过DOM Tree 和 CSS Rule Tree 来构造 Rendering Tree。注意: Rendering Tree 渲染树并不等同于DOM树,因为一些像Header或display:none的东西就没必要放在渲染树中了。CSS 的 Rule Tree主要是为了完成匹配并把CSS Rule附加上Rendering Tree上的每个Element。也就是DOM结点。也就是所谓的Frame。然后,计算每个Frame(也就是每个Element)的位置,这又叫layout和reflow过程。3)最后通过调用操作系统Native GUI的API绘制。 线程js 是单线程,但是浏览器是多线程的。 浏览器会有不同的线程,比如说 GUI 渲染线程JS 线程定时器触发线程 (setTimeout)浏览器事件线程 (onclick)http 异步线程.....上面的几个线程,在同一个瞬间,只有一个线程起作用,也就是互斥的。比如说浏览器在执行GUI 渲染线程呢,那么其他的4个进程,都处于挂起的状态,在队列里面呆着。DOM的渲染对应的就是GUI渲染进程;JS的执行对应的就是JS线程;所以,DOM的渲染与JS代码的运行,在同一瞬间只能有一个执行! 阻塞阻塞XXX是指让XXX暂停了。比如JS的执行阻塞DOM解析,就是 DOM解析 --> JS执行(此时DOM解析暂停) --> JS执行完毕 --> DOM继续解析 DOM与CSS先看它俩之间的关系,也就是分析CSS的加载对DOM的解析和渲染的影响。很明显,DOM自己在那解析DOM TREE 和 css样式有啥关系啊,所以css不影响DOM解析。也很明显,DOM渲染就是要生成样式呢,肯定和css有关系啊,所以css影响DOM渲染。结论: ...

June 25, 2019 · 1 min · jiezi

Commit-message-代码提交规范

Commit message 代码提交规范**前言**在多人协作项目中,如果代码风格统一、代码提交信息的说明准确,那么在后期协作以及Bug处理时会更加方便。Git 每次提交代码,都要写 Commit message(提交说明),否则就不允许提交。一般来说,commit message 应该清晰明了,说明本次提交的目的。 Commit message 的作用 ● 提供更多的历史信息,方便快速浏览● 过滤某些commit(比如文档改动),便于快速查找信息● 直接从commit生成Change log● 可读性好,清晰,不必深入看代码即可了解当前commit的作用。● 为 Code Reviewing(代码审查)做准备● 方便跟踪工程历史● 提高项目的整体质量,提高个人工程素质Commit message 的格式 Commit message 包括三个部分:Header,Body 和 Footer <type>(<scope>): <subject>// 空一行<body>// 空一行<footer>一、Header Header部分只有一行,包括三个字段:type(必需)、scope(可选)和subject(必需)(1)type type用于说明 commit 的类别,只允许使用下面的标识 feat:新增功能(feature) fix:修补bug docs:仅仅修改了文档,比如 README, CHANGELOG, CONTRIBUTE等等 style: 仅仅修改了空格、格式缩进、逗号等等,不改变代码逻辑 refactor:重构(即不是新增功能,也不是修改bug的代码变动) test:增加测试,包括单元测试、集成测试等 chore:构建过程或辅助工具的变动 type:代表某次提交的类型,比如是修复一个bug还是增加一个新的feature。 perf: 优化相关,比如提升性能、体验 revert: 回滚到上一个版本 ci:自动化流程配置修改注:如果type为feat和fix,则该 commit 将肯定出现在 Change log 之中 (2)scope scope用于说明 commit 影响的范围,比如数据层、控制层、视图层等等,视项目不同而不同。(3)subject ...

June 25, 2019 · 2 min · jiezi

大数据时代浅谈医疗数据分析在医疗领域的运用

随着医疗卫生信息化迅速发展 医学研究正步入大数据时代 大数据的许多承诺正在医疗行业变成现实 大数据的实时处理和数据分析 可以让医疗领域的从业者 更快更全面的做出决策和行动 该领域正在慢慢成熟 随着云计算、物联网、移动互联网等新技术水平的提高,各行各业所累计的数据已经呈现指数级的增长。“大数据” 时代已经出现。 近年来,大数据解决方案与大数据分析工具开始被广泛运用于医疗卫生领域。通过数据,可以把医学专家积累的宝贵经验,转化成标准化的知识基础,做到数据驱动医疗服务,因此从而大大提高服务能力和效率,解决中国医疗领域存在的诸多需求。然而健康医疗大数据究竟指的是何种数据?其“大”又体现在何处? 一.大数据 大数据的类型大致可以分为以下两种: 第一种类型是通过对海量数据进行分析,获得巨大价值的产品、服务和见解,我们称之为“动词定义”。 第二种类型是基于多源异构、跨域关联的海量数据(数据量、数据形态、数据分析处理方式),通过分析所产生的决策流程、商业模式、科学范式、生活方式和观念形态上的颠覆性变化的总和,我们称之为“名词定义”。 二.医疗数据 医生对患者诊疗和治疗过程中产生的数据,包括患者的基本数据、电子病历、诊疗数据、医学影像数据、医学管理、经济数据、医疗设备和仪器数据等,以患者为中心,成为医疗数据的主要来源。 三.医疗数据来源 首先来讲,“医疗数据”的主要来源有四个方面,第一种是患者就医,第二种是临床研究和科研,第三种是生命制药,第四种是可穿戴设备。 第一种“患者就医”,源于患者,患者的体征数据、患者的化验数据、患者的描述,患者的住院数据、医生对患者的问诊数据、医生对患者的临床诊治、用药、手术等数据。 第二种“临床研究和科研”主要是实验中产生的数据,也包含患者产生的数据。 第三种“生命制药”主要是实验产生的数据,与用药相关的用药量,用药时间,用药成分,实验对象反应时间,症状改善表象等数据,与生命等基因组学相关的数据。 第四种“可穿戴设备”主要通过各种穿戴设备(手环、起搏器、眼镜等)收集人体的各种体征数据。 四.医疗数据特性 医疗数据首先它属于数据的一种,所以其大数据也必定具备一般的数据特性:规模大、结构多样、增长快速、价值巨大,但是其作为医疗领域产生的数据也同样具备医疗性:多态性、不完整性、冗余性、时间性、隐私性。 多态性:医疗数据包含有像化验产生的纯数据,也会有像体检产生的图像数据类似心电图等信号图谱,医生对患者的症状描述以及跟进自己经验或者数据结果做出的判断等文字描述,另外还有像心跳声,哭声,咳嗽声等类似的声音资料,同时现代医院的数据中还有各种动画数据(像胎动的影像等)。 不完整性:由于各种原因导致有很多医学数据是不完整的,像医生的主观判断以及文字描述的不完整,患者治疗中断导致的数据不完整,患者描述不清导致的数据不完整等。 冗余性:医疗数据量巨大,每天会产生大量多余的数据,这给数据分析的筛选带来了很大困难。 时间性:大多医疗数据都是具有时间性、持续性的,像心电图,胎动思维图均属于时间维度内的数据变化图谱。 隐私性:隐私性也是医疗数据的一个重要特性,同时也是现在大部分医疗数据不愿对外开放的一个原因,很多医院的临床数据系统都是相对独立的局域网络,甚至不会去对外联网。 五、数据的处理 数据的处理一般分为6个步骤:挖掘数据、收集数据、分析数据、存储数据、数据转化实用,最终在实用过程中产生数据,如此循环。 六.医疗大数据的用途 医疗大数据的主要用途有:用药分析、病因分析、移动医疗、基因组学、疾病预防、可穿戴医疗等。 随着医疗大数据的发展和分析方法、人工智能等技术的不断革新,能够准确利用医疗大数据来进行分析和预测的场景会越来越多,到时大数据将会成为医疗决策的一种重要辅助依据。 七.医疗大数据 医疗大数据企业主要分为三类:慢病及健康管理(辅助患者)、临床决策支持(辅助医生)、医药研发。 医疗大数据的服务对象主要有:居民、医生、科研、管理机构、公众健康。 医疗大数据的主要用途有:用药分析、病因分析、移动医疗、基因组学、疾病预防、可穿戴医疗等。 八.统计学在医疗方面的运用 统计学是医学科学研究的重要工具,运用概率论与数理统计的原理及方法,结合医学实际,研究数字资料的搜集、整进行理分析与推断。正确的统计分析能够帮助人们正确认识客观事物的规律性,做到胸中有数,有的放矢地开展工作,提高工作质量。 在统计分析领域中,有一种用途极其广泛的特征曲线,叫做接受者操作特性曲线。 得此名的原因在于曲线上各点反映着相同的感受性,它们都是对同一信号刺激的反应,只不过是在几种不同的判定标准下所得的结果而已。 接受者操作特性曲线就是以虚惊概率为横轴,击中概率为纵轴所组成的坐标图,和被试在特定刺激条件下由于采用不同的判断标准得出的不同结果画出的曲线。 在统计学中常讲到的AUC就是”Area Under the ROC curve“,它的值是介于0.1到1之间,是当前分类算法根据计算所得的一个score值,AUC值越大说明正样本越有可能排在负样本之前,从而能更好进行统计样本的分类。 在现有的一个统计学方法中,我们对样本的诊断通常是分为两类,一个是健康类,另一类是得病类。除了这两类以外,还存在一种人群叫亚健康人群,如果我们还是按照原有的方法去给病人进行分类的话,那么我们所得到的一些结果可能是具有误导性的。 在统计学中概率样本的置信区间是对样本的某个总体参数的区间,估计通常来说,比如说我们说有95%的置信区间,那么就是说测试者有95%的统计量是落在置信区间内的。 它其实展示了这个参数的真实值,有一定概率落在测试结果周围的一个程度,也给出被测量参数测试测量值的一个可信程度。 怎么去判断这个诊断的一个精确性,我们需要看的是置信区间的一个覆盖率,如果这个覆盖率越接近于既定的一个概率的话,那么这个方法就越精确。 广泛搜寻,就是把所有的值结合在一起,然后去比较它们之间的大小,用这种比对的方法来找出最大的不同。 如此可见,随着医疗服务提供者越来越善于从患者数据中提取有意义的见解,他们也将学习更好的提供治疗的方法,提高服务质量。随着大数据技术领域的成熟,许多组织将受益于运营的改善、费用的降低和健康状况的改善。 通过许多方式,大数据和人工智能可以帮助解决日益严重的护理提供者短缺问题。医疗服务提供商也将充分利用大数据技术为医疗技术框架持续提供动力。

June 25, 2019 · 1 min · jiezi

平时遇到的问题整理包括h5PC小程序

这篇文章主要整理了一些平时遇到的问题,不定时更新,仅供自己学习所用。若有更好的解决方案,欢迎指出~ 有关h5部分19/4/12问题描述:PC端用textarea获取数据,经过后端,传到h5页面显示。遇到换行等操作,不能正常显示。解决方法:textarea内容有换行等操作经过数据库后显示不正常问题解释:关于该问题,网上还有其他的方法,多是用'<br>'换掉'\n',但如果文中输入'\n'这样的字符串,显示就会有问题,就会自动换行,上面这个方法就没有这样的问题了。 pre 元素可定义预格式化的文本,被包围在 pre 元素中的文本通常会保留空格和换行符,而文本也会呈现为等宽字体。19/4/16问题描述:写h5和小程序与PC最大不同是字体大小的设置。解决方法:加一个文件mixins.scss,里面内容如下(这个栗子是针对h5,小程序也同样适用): @function strip-units($number) { @return $number / ($number * 0 + 1);}// px change to rem@function rem($px) { @return strip-units($px) / 50 + rem;}有关微信小程序部分19/6/25接手了一个别人写的小程序,然后给我提了很多bug,都是一些细节问题。问题描述:手机上的后退键,后退的页面不是产品所想要的页面。解决方法:只要好好了解小程序的路由,这个问题修改起来就很容易。这下面是官方文档里面介绍的路由,最重要的是标红的三种写法:先说navigateTo,它的意思就是把下一个页面入栈(栈就是将页面后进先出的一个容器);reLaunch表示的是跳转到某个页面,并把栈里面的页面数据都清除,只保留下一个页面;redirectTo表示销毁当页(又把当前页从栈中拿出并销毁,这是和navigateTo最大的区别),把下一页入栈。 问题描述:ios手机时间显示错误,显示为NaN。解决方法:这是因为ios系统不支持“yyyy-mm-dd”这样的格式,要替换成“yyyy/mm/dd”的格式,用.replace(/-/g, '/')就好,具体方案可以看这ios时间显示问题 问题描述:微信开发工具上图片可以显示,但是到了真机就不显示。解决方法:那是域名信息没有备案,并且微信开发工具关闭了校验。

June 25, 2019 · 1 min · jiezi

怎么用视频转换器将qlv格式转换成mp4

随着电子设备的不断普及,我国的互联网普及率越来越高。而在这个科技飞速发展的时代大家喜欢看剧用以打发时间,而腾讯视频的用户量占据了视频播放器的半壁江山。因为腾讯视频有自己的qlv文件加密机制所以无法用其他播放器打开qlv文件。但使用视频转换器可以快速的将qlv格式转换成mp4。接下来就教大家在怎么用迅捷视频转换器将qlv格式转换成mp4。 在将qlv格式转换成mp4之前我们要先准备好腾讯视频客户端和迅捷视频转换器。准备好这两款软件后首先到腾讯视频客户端下载自己需要转换的视频(此时的文件格式依旧为腾讯视频自带的qlv格式)。 之后下载并安装迅捷视频转换器,安装好后软件一般会在桌面生成一个快捷方式,随后双击快捷方式进入软件。在进入软件后可以先注册并登录软件,也可以直接用第三方登录(QQ/微信)的形式登录软件。 登录好软件后可以将我们之前在腾讯视频下载好的qlv格式的文件添加到软件中。添加的方式有很多种,可以点击左上角的“添加文件”或“添加文件夹”按钮,也可以使用直接拖拽或者点击软件中间部分的方式添加文件。 将文件添加至文件后首先将输出格式选择为mp4同原文件(也可以设置成其它格式或者其它分辨率),然后点击“更改路径”按钮设置好输出路径,之后点击右上方的“转换”(或者右下方的“全部转换”)按钮进行格式转换。 在点击完“转换”或“全部转换”按钮后等待一会迅捷视频转换器就会把qlv转换成mp4格式。当软件中的进度条到达“100%”时就表示迅捷视频转换器已经成功把腾讯视频原有的qlv格式转换成mp4了。 最后只需要找到之前预设的输出路径或者直接点击迅捷视频转换器中的“打开”按钮就可以打开格式为mp4的视频了。 看完以上步骤是不是发现qlv格式转换成mp4其实很简单呢?那么现在你是否还在为怎么将qlv格式转换成mp4而苦恼呢?那就用上述的详细教程把腾讯视频下载的qlv格式转换成mp4吧。 迅捷视频转换器https://www.xunjieshipin.com/...

June 25, 2019 · 1 min · jiezi

详解-HTML-attribute-和-DOM-property

在大多数的文章中,attribute 一般被翻译为“特性”,property 被译为“属性”。 结论把结论写在最前面,如果你全都懂,后面就不用看了。 HTML attributeDOM property值永远是字符串或 null值可以是任意合法 js 类型大小写不敏感大小写敏感不存在时返回 null不存在时返回 undefined对于 href, 返回 html 设置的值对于 href 返回解析后的完整 url更新 value, 属性也更新更新 value, 特性不更新概述当我们书写 HTML 代码的时候,我们为 HTML <abbr title="Element">元素</abbr>设置<abbr title="attribute">特性</abbr> ,例如: <input id="name" value="justjavac" />我们写了一个 input 标签,并给他定义了 2 个<abbr title="attribute">特性</abbr> (id 和 value)。当浏览器解析这段代码的时候,会把 html 源码解析为 DOM 对象,确切的说是解析为 HTMLInputElement 对象。HTMLInputElement 的继承关系是: HTMLInputElement ↓HTMLElement ↓Element ↓Node ↓EventTarget ↓Object通过查看文档会发现,HTMLInputElement 的原型上定义了很多<abbr title="property">属性</abbr>和方法,例如 form, name, type, alt, checked, src, value 等等,还有从 HTMLElement 继承来的 id, title, clientTop 等等。 如果仔细找找,就不难发现其中就有我们为 input 标签定义的<abbr title="attribute">特性</abbr>:id 和 value。当浏览器解析网页时,将 HTML <abbr title="attribute">特性</abbr>映射为了 DOM <abbr title="property">属性</abbr>。 ...

June 25, 2019 · 2 min · jiezi

译asyncawait-应知应会

原文地址: https://hackernoon.com/javasc...原文作者: Charlee Li 翻译作者: Xixi20160512 async/await 是在 ES7 版本中引入的,它对于 JavaScript 中的异步编程而言是一个巨大的提升。它可以让我们以同步的方式处理异步的流程,同时不会阻塞主线程。但是,想要用好这一特性,可能需要动点脑筋。本文中,我们将从不同的角度探讨 async/await,同时会展示如何正确和高效的使用它们。 async/await 的优点async/await带给我们最大的一个好处就是同步的编程风格。让我们看一个例子: // async/awaitasync getBooksByAuthorWithAwait(authorId) { const books = await bookModel.fetchAll(); return books.filter(b => b.authorId === authorId);}// promisegetBooksByAuthorWithPromise(authorId) { return bookModel.fetchAll() .then(books => books.filter(b => b.authorId === authorId));}很明显,async/await 的版本比 promise 的版本更加的易于理解。如果你忽略 await 关键字,这段代码看起来就像任何其他的同步式语言(比如说 Python)。 不仅仅是可读性,async/await 有浏览器的原生支持。到今天为止,所有主流浏览器都支持 async 函数。 所有主流浏览器都支持 async 函数。(图片来源:https://caniuse.com/) 原生支持意味着你不需要编译代码。更重要的是,这个将有助于调试。当你在 async 方法的入口打一个断点并且步进到 await 这一行的时候,你将会看到调试器在 bookModel.fetchAll() 这个函数执行的时候等待了一会儿,然后才会走到接下来的 .filter 这一行!和 promise 的示例比较起来,这个容易多了,因为你必须在 .filter 这一行再打一个断点。 ...

June 25, 2019 · 3 min · jiezi

响应式-媒体查询

响应式我自己的理解就是限制住像素范围然后分别写入一套cssHTML就写两套或者更多 但只显示一套 其实吧现在!!!很少有网站是用响应式写的主流的一些像是 某宝 某东 都是用js判断也就是做一个pc端 一个移动端 看用户用的是电脑还是手机根据判断结果 更改页面地址 那为什么还要学呢。。。应付面试啊! 反正又不难学就学喽 方法1 -- css写法// CSS@media(max-width:320){ // 320像素以下执行里面的css 范围:0 ~ 320 body{ background:red }}@media(min-width:321) and ( max-width:375 ){ // css 范围:321 ~ 375 body{ background:blue }}@media(min-width:376){ // css 范围:376 ~ 正无穷 body{ background:purple }}方法2 -- link写法用文件代替内容<!-- HTML --><head> <!-- 这个css 在该范围下才会生效 --> <link rel='stylesheel' href='style.css' media='(max-width:320px)'/></head>应用做响应式的时候:先做手机 再做网站 --- Mobile first 【推荐】先做网站 再做手机 --- Desktop first用js判断一下是网站还是手机并写入不同的地址 //jsfunction judge(){ if((navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i))) { //window.location.href="移动端url"; alert("mobile") } else { // window.location.href="pc端url"; alert("pc") }}judge();meta 标签作用:标签就是告诉浏览器, 不要在移动端显示的时候缩放<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1">

June 25, 2019 · 1 min · jiezi

css布局如何实现垂直居中

css布局:如何实现垂直居中?1.利用line-height实现居中,这种方法适合纯文字类的; <!-- css --><style>.parents { height: 400px; line-height: 400px; width: 400px; border: 1px solid red; text-align: center;}.child { background-color: blue; color: #fff;} </style></head><body><!-- html --><div class="parents"> <span class="child">css布局,实现垂直居中</span></div></body>2.通过设置父容器相对定位,子级设置绝对定位,标签通过margin实现自适应居中; <!-- css --><style>.parents { height: 400px; width: 400px; border: 1px solid red; position: relative;}.child { width: 200px; height: 100px; line-height: 100px; text-align: center; color: #fff; background-color: blue; /* 四个方向设置为0, 然后通过margin为auto自适应居中 */ position: absolute; top: 0; right: 0; bottom: 0; left: 0; margin: auto;} </style></head><body><!-- html --><div class="parents"> <span class="child">css布局,实现垂直居中</span></div></body>3.弹性布局flex 父级设置display: flex; 子级设置margin为auto实现自适应居中; ...

June 25, 2019 · 2 min · jiezi

带着canvas去流浪8碰撞

示例代码托管在:http://www.github.com/dashnowords/blogs博客园地址:《大史住在大前端》原创博文目录 华为云社区地址:【你要的前端打怪升级指南】 [TOC] 经过前面章节相对枯燥的练习,相信你已经能够上手canvas的原生API了,那么从这一节开始,我们就开始接触点好玩的东西——动画。 一. canvas的能力如果你以为canvas只能绘制图表那真的就图样图森破了,且不谈webgl的绘图上下文,单就2d空间的画笔就可以做很多有意思的事情,比如实现一些酷炫的动画效果,比如做一些物理仿真,图片滤镜,直播弹幕,甚至做游戏开发等等,画面的变化大多依赖于canvas提供的像素操作能力,而动效几乎都是靠canvas在短时间内逐帧绘制而形成的,和电影的原理是一样的。 我们知道javascript中和时间控制有关的函数setTimeout( ) 以及setInterval( )最终执行时的时间点并不准确,因为在事件队列中会被其他异步任务影响甚至直接阻塞,那么在不断重复的绘制中,就有可能会出现卡顿或者忽快忽慢;另一方面,假设我们使用的电脑显示屏刷新率为60帧/秒,也就是大约16.7ms重绘一次,那么即时我们在16.7ms时间内执行了很多次计算和绘制命令,实际上最终呈现出的也只是最后一次结果,就好比对一段很密集的数据进行了隔点采样,轻则浪费性能,重则会在画面呈现时出现跳帧。为了配合显示器刷新,我们可以使用另一个方法——requestAnimationFrame(fn),这是javascript中专门用来绘制逐帧动画的,它会配合显示器的刷新频率进行必要的图像更新,节省不必要的性能浪费。 二. 动画框架在canvas上实现基本的动画,可以遵循一个基本的编程框架: function step(){ /** *在每一帧中要执行的逻辑 *...... */ requestAnimationFrame(step);}step();//启动执行你没看错,这就是canvas动画最核心的一段代码,step()函数会在每个绘图周期内重复执行。那么每一帧中需要做哪些工作呢? 我们将canvas想象成一个舞台stage,每一个需要绘制在画布上的元素被称为精灵,无论它们拥有怎样的属性,它们都具备update( )和paint( )两个基本方法,前者用于在每一帧中计算更新精灵的参数属性,后者用于将这个精灵对象绘制在画布上。那么step函数在每一帧中所执行的逻辑就变得明朗了,对画布进行必要的擦除,接着更新每一个精灵的状态(可能是位置,颜色等等),然后将其绘制在画布上。 比如现在要在画布上表现一段太阳东升西落得动画,对应的伪代码就是下面这个样子的: let stage = [];stage.push(background, tree, cloud, sun);function step(){ cleanStage();//对画布进行必要擦除 background.update();//更新土地的属性 tree.update();//更新树的属性 cloud.update();//更新云的属性 sun.update();//更新太阳的属性(属性中必然包含着太阳的位置数据) background.paint();//绘制土地 tree.paint();//绘制树 cloud.paint();//绘制云 sun.paint();//绘制太阳 requestAnimationFrame(step);}如果你理解了上面的过程,那么接下来我们对上述代码进行一些抽象和改写: //建立舞台及添加元素的代码let stage = [];stage.push(background, tree, cloud, sun....);//逐帧动画代码function step(){ cleanStage(); stage.map(sprite=>{ sprite,update(); sprite.paint(ctx); }); requestAnimationFrame(step);}每一个精灵对象都需要实现自己的update( )和 paint( )方法来描述自己的参数如何变化,以及如何在每一帧中被绘制,被添加进stage数组的都是精灵的实例,一般会将canvas绘图上下文传入paint(context)方法,这样就可以将精灵绘制在指定的画布上。上面的范式只是一个简陋的核心模型,但是已经足够说明canvas动画的本质。 三. 在canvas中模拟碰撞现在我们就通过一个碰撞仿真的例子来学习canvas动画以及基本的物理仿真分析,示例虽然精简,但包含了canvas动效最核心的精灵动画和碰撞检测主题。为了方便二维向量操作并隐藏各种数学计算的细节,我们直接使用一个已经定义好的Vector2类,其中封装了很多向量的基本操作,都是初高中数学的知识,如果你已经记不太清楚,可以找一些有关的资料复习一下。 3.1定义小球的属性将每一个小球视为一个精灵,我们需要为它增加一些基本属性以便在每一帧中能够将其绘制出来。通过位置,半径和颜色信息,就能够绘制出小球;通过速度信息,就可以计算小球的位置变化,以便在绘制下一帧时使用。 class Ball{ constructor(x,y,id){ this.pos = new Vector2(x,y);//初始化小球的位置 this.id = id; this.color = '';//绘制的颜色 this.r = 20;//小球半径,为方便演示,此处使用给定值 this.velocity = null;//小球的速度 }}3.2 生成新的小球为了增加演示效果,我们使用一个定时函数来随机生成小球,每次生成时为其赋予一个颜色,并给定一个随机的初始速度。 ...

June 24, 2019 · 2 min · jiezi

感受下免费的服务器三丰云

发现了一个提供免费服务器的厂商三丰云,可以提供高配高宽带的免费服务器,大家可以看看感受下. 领取地址:https://www.sanfengyun.com/fr... 这里有免费的服务器,可以连接使用下.

June 24, 2019 · 1 min · jiezi

从GGEditor的一个案例看JS原生拖拽功能

拖拽操作平时用的比较少,在最近的一个项目中使用到了,并且踩了一些坑,本文做一个简单的总结。涉及部分G6的API,不会对理解全局产生干扰。需求概述如下图所示,左侧为GGEditor元素面板React组件,右侧为G6画布,现需要将元素从「元素面板」中拖拽到「画布」上。要求: 拖拽时蓝色虚线框和元素面板的对应元素尺寸相同(为一矩形)蓝色虚线框跟随鼠标移动,指明当前拖拽的位置元素面板上对应元素不应发生改变 ⚠️图中的黑色圆圈仅为录屏软件指明鼠标操作提示 拖拽方法总结相较于大部分DOM操作只需要监听某一种事件,原生拖拽功能的实现通常需要监听全部或部分的下述事件: 事件event.target触发时机drag被拖动元素拖拽中(每几百毫秒触发一次)dragstart被拖动元素刚开始拖拽dragend被拖动元素拖拽结束(鼠标释放或esc)dragover被拖动元素下方元素拖拽到某一目标上时(每几百毫秒一次)dragenter被拖动元素下方元素被拖动元素进入可释放处时dragleave被拖动元素下方元素拖拽离开某一目标时drop被拖动元素下方元素同dragend 且在其之前触发需求实现实现之前,有几个踩坑点先说明: 不能将左侧面板的元素设置为draggable,因为原生拖拽自带阴影效果,如下图。很明显这不是我们要的效果。 拖拽时的蓝色虚线框应该由G6绘制成一个canvas的元素,因为画布可以放大或缩小,这个虚线框应和实际放在画布上的元素尺寸相同而不是左侧面板的元素尺寸相同。(不了解G6的同学自行忽略)思路拖拽开始或鼠标落下时,创建一个和元素大小宽高相同的透明度为0的矩形shadowShape,并监听其drag,mouseup事件。在document上监听dragenter事件,当target为画布时,通过G6api创建一个蓝色虚线框dragShapeshadowShape移动的时候,更新dragShape的位置在document上监听drop事件,落在画布时,创建一个G6的节点从而完成整个拖拽添加元素的功能。⚠️踩坑点:必须要阻止dragover的默认行为,保证drop的正常触发,参考这则问答 总结1 相较于上个版本的GGEditor,实现了拖拽功能的连续性。之前,鼠标即使保持按下,一旦移出画布,就终止了本次的拖拽过程。 上个版本的GGEditor 2 待优化点: 由于蓝色虚线框是G6画布上的元素,能够根据G6的缩放比例自动调整大小,所以在其他地方的拖拽过程不易做出类似的虚线框,体验上有间断感当前代码在一个react组件里操作了大量的原生事件监听,不够React,考虑之后直接开发一个新的组件,使用React的合成事件来重写。

June 24, 2019 · 1 min · jiezi

百度都找不到的资源被这5个资源网站搜到了

每次遇到什么不会的东西,第一时间想到的就是--上百度!实际上我们在百度上也只会翻看前面两页,相信没有多少人会一直翻看后面的内容。这样直接导致我们搜索的内容很有局限性。 实际上我们可以在别的搜索引擎网站进行搜索,这些资源百度都不一定搜索出来! 1.傻逼吧 该网站是一款不可多得的资源搜索网站,精准高效的为你提供各类bt资源搜索,包括电影、音乐、图书、软件、教程、图片、综艺等内容,想看什么搜搜就知道! 2.巴哈姆特动画疯 该网站是一款动画类的网站,喜欢看动漫的朋友们只需要打开网站就能免费观看了,而且网站每天都有更新,资源异常丰富,非常好用! 3.万千合集站 如果大家需要查询论文,文档搜索,该网站都能统统满足你!不仅能搜索你想要的论文,重点是还能免费下载下来,妥妥的5颗星网站! 4.红袖添香 喜欢看小说的朋友过来凑个热闹,该网站提供了各种小说,包括言情、古侠、灵异、青春小说,网站全场免费畅读,喜欢的小伙伴们赶紧收藏了! 5.屌丝青年 听名字还以为是这个网站很“屌丝”,其实这个网站的资源却不“屌丝”,相反网站资源很实在,可以搜索教程、视频、软件、电视剧等各类精品资源,你用了就知道! 怎么样,今天小编介绍的资源搜索网站你们有收藏吗?还没收藏的赶紧收藏下来!

June 24, 2019 · 1 min · jiezi

element-ui单选框radio与弹出框Popover混用失灵

<el-radio-group v-model="form.buyType"> <el-radio label="我是单选框a"></el-radio> <el-popover placement="bottom" title="" width="200" trigger="click" content="哈哈,我是弹出框里的内容"> <button @click="form.buyType='按使用用户人数购买'" style="background-color: transparent;border: none;" slot="reference"> <el-radio label="我是单选框b"></el-radio> </button> </el-popover> </el-radio-group>解读:如果用el-popover直接包el-radio的话,在click类型下,弹出框会一闪就消失,笔者这里用button包住el-radio,将原样式隐藏,手动获取el-radio焦点来实现两者混用。 本文属于作者原创,转载请注明出处。

June 24, 2019 · 1 min · jiezi

原来没有网络也能扫码支付都是因为它啊

现在网络越来越发达,一般人平时出门也就带个手机,就可以满足日常所需。支付宝和微信是目前主流的移动支付方式,付款时,我们只需要出示我们的付款二维码,商家扫一扫即可完成收款了,非常方便。 是大家有没有发现,当我们的手机没有网络的情况下,手机竟然也能完成支付,这是怎么实现的呢? 无网络情况下,生成离线码 其实,在我们的手机没有网络的时候,手机里生成的这个付款二维码叫做离线码。支付软件会给每个用户分配一个独一无二的身份识别, 叫做种子数据。 当我们手机没有网络的时候,支付软件的程序会根据算法、种子数据、时间等生成一个特别的二维码。商家的扫码枪轻轻一扫,就把这个码的数据返回给支付软件核对,一旦双方数据核对一致,这个支付就成功啦~ 但是在这种情况下,有一点需要注意,用户手机可以没有网络,但是商家的扫码枪、系统以及支付软件的系统必须是在线的,也就是必须连接到网络上,否则就无法核对数据,支付就会失败。 这个离线码会被盗用吗 有机友担心,既然是离线码,那别人是不是可以直接截图使用?万一被别人恶意拍到了,是不是就会被别人随意刷用金额了? 这个是完全不用担心的,因为这个离线码是包含了用户识别、身份识别、令牌等信息,是有唯一性的,而且这个离线码是每60秒就自动更新一次,当我们自己付款成功之后,这个离线码也就失效了,别人拍了也是不能用的,不必担忧会给自己造成经济损失。 什么情况下手机必须有网络 一般在大超市或者规模比较大的商店,商家才会有扫码枪,如果是小店甚至小摊,一般是需要我们扫商家的二维码来付款的。在这个过程,我们的手机扫到二维码之后,还需要填写金额、输入密码、点击确认等一系列操作才能完成支付。 此时,我们的手机就相当于扫码枪,商家的二维码就相当于离线码,就如前面说的,扫码枪是必须在线的,所以我们的手机必须有网络,不然就无法完成支付。 为什么不需要输入密码就能支付 有细心的机友还发现了一个问题,为什么商家的扫码枪一扫,我们手机里的钱就被扣走了,难道不需要我们来输入密码吗?这安全吗? 其实,这个也不用特别担心,这里有3点可以保证我们的资金安全! 01扫码枪资质 扫码枪是要有专门的商店资质才能获取的权利,商家需要递交正规的资料才会申请通过,所以一些不良商家是没有这个功能的。 02金额上限 一般数额不大的情况下,付款是不需要密码的。但是如果付款的金额比较大,付款时会提示需要输入密码才会正常进行交易。另外,超市售货员会在屏幕上面打出金额,我们可以留意一下金额是否正确。 03自定义免密支付 扫码枪能完成免输入密码支付,一方面是因为我们自己开通了免密支付,授权给支付宝和微信,然后支付宝或微信再授权给商家,都是正规的渠道,安全性上完全可以放心。如果担心资金安全,可以取消免密支付协议,这样以后付款就需要手动输入密码了。 在日常生活中,大家有没有遇到因为没有网络而支付失败的糗事呢?欢迎评论区分享你的故事。

June 24, 2019 · 1 min · jiezi

如何快速去除抖音视频水印

说起抖音短视频,近两年来很多产品都火爆起来,像火山小视频、快手等等,而最火的非抖音短视频莫属了。但是在下载到喜欢的视频后发现每个视频都有水印会让人感觉不舒服,不禁会想如何做到抖音去水印呢?今天小编就告诉你怎么用迅捷视频转换器快速去除抖音短视频视频水印,方便快捷又简单。 操作步骤 1、首先打开抖音短视频在里面找到自己喜欢的视频,在抖音短视频找到“保存本地”并点击“保存本地”按钮把视频保存到本地文件中(抖音短视频的默认保存格式为mp4格式)。 2、找到迅捷视频转换器(分为手机版和电脑版,小编习惯使用电脑版去水印)并打开软件选择软件中的“视频去水印”按钮跳转到去水印的界面。 3、点击“添加文件”按钮把抖音短视频下载好的文件放入到迅捷视频转换器中(支持上传mp4、rmvb、avi、mkv等多种视频格式。),然后选择好要保存的视频输出格式和将要输出的文件输出路径后点击“编辑去水印”按钮准备去除水印。 4、点击“添加去水印区域”将蓝色的矩形框移动到有水印的区域并且调整蓝色矩形框的大小把水印调整至蓝色矩形框内点击“确定”按钮,当不小心选错区域时还可以点击“删除选中区域”重新选则去水印区域去除抖音短视频水印。 5、在完成以上步骤后等待大致10秒的时间迅捷视频转换器就会自动把抖音短视频的水印去除。最后在自己之前设置好的输出路径找到去水印后的文件就可以看到没有水印的视频文件啦。 迅捷视频转换器不仅支持可以用去除抖音短视频的水印,有需要的话还可以去除各大短视频和播放器所带来的视频水印。同时还支持手机APP去除视频水印。 看完上述完整的迅捷视频转换器去水印步骤你是否还在纠结如何做到抖音去水印呢?其实抖音短视频去除水印是很简单的呢,赶紧去抖音短视频下载短视频试试如何去除视频水印呀!

June 24, 2019 · 1 min · jiezi

StepByStep高频面试题深入解析-周刊05

关于【Step-By-Step】Step-By-Step (点击进入项目) 是我于 2019-05-20 开始的一个项目,每个工作日发布一道面试题。每个周末我会仔细阅读大家的答案,整理最一份较优答案出来,因本人水平有限,有误的地方,大家及时指正。 如果想 加群 学习,可以通过文末的公众号,添加我为好友。 __ 本周面试题一览:实现 Promise.race 方法JSONP 原理及简单实现实现一个数组去重的方法清楚浮动的方法有哪些编写一个通用的柯里化函数 currying20. 实现 Promise.race 方法在实现 Promise.race 方法之前,我们首先要知道 Promise.race 的功能和特点,因为在清楚了 Promise.race 功能和特点的情况下,我们才能进一步去写实现。 Promise.race 功能Promise.race(iterable) 返回一个 promise,一旦 iterable 中的一个 promise 状态是 fulfilled / rejected ,那么 Promise.race 返回的 promise 状态是 fulfilled / rejected. let p = Promise.race([p1, p2, p3]);只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给 p 的回调函数。 Promise.race 的特点Promise.race 的返回值是一个 promise 实例如果传入的参数为空的可迭代对象,那么 Promise.race 返回的 promise 永远是 pending 态如果传入的参数中不包含任何 promise,Promise.race 会返回一个处理中(pending)的 promise如果 iterable 包含一个或多个非 promise 值或已经解决的promise,则 Promise.race 将解析为 iterable 中找到的第一个值。Promise.race 的实现Promise.race = function (promises) { //promises传入的是可迭代对象(省略参数合法性判断) promises = Array.from(promises);//将可迭代对象转换为数组 return new Promise((resolve, reject) => { if (promises.length === 0) { //空的可迭代对象; //用于在pending态 } else { for (let i = 0; i < promises.length; i++) { Promise.resolve(promises[i]).then((data) => { resolve(data); }).catch((reason) => { reject(reason); }) } } });}21. JSONP原理及简单实现尽管浏览器有同源策略,但是 <script> 标签的 src 属性不会被同源策略所约束,可以获取任意服务器上的脚本并执行。jsonp 通过插入 script 标签的方式来实现跨域,参数只能通过 url 传入,仅能支持 get 请求。 ...

June 24, 2019 · 3 min · jiezi

前端进阶1为什么要制定开发规范

0 为什么要有规范?与性能无关与功能无关与效果无关与能力无关与工期无关但是,规范必不可少 与效率相关(开发、迭代和维护,重点提升维护及迭代效率)与团队相关(减少团队之间的不一致性)与面试相关(提高代码健壮性,通过面试)与习惯相关(保证最近实践)与开源相关(开源项目均有严格的开发规范)1 效率代码风格(eslint)书写规范(eslint)1.1 易读1.1.1 空格(英文、数字与中文结合)// 不理想 <p>AlexShan毕业于2008年</p>// 理想 <p>AlexShan 毕业于 2008 年</p>数字、英文与中文直接左右应该留有 1 个空格1.1.2. 习惯布局// 不好的布局风格,用行内元素包裹块级元素(新的 ESlint 规则默认禁止如此布局)<span> <div> <p><div class='strong'>不好</div>的布局风格</p> </div></span>// 较好的布局 <div> <p><strong class="strong">较好</strong>布局风格</p></div>我们应该合理选择和使用html中的DOM元素进行页面布局换行// 无换行<div v-vstop class="moreData" @mouseenter="showWin(index,'showindex')" @mouseleave="showindex=-1"> <i class="icon iconfont icon-showdown" :class="{'icon-showup':showindex==index}" ></i> <i class="icon iconfont icon-left-arrow" v-show="showindex==index"></i> <div class="mpanel" v-show="showindex==index"> <div v-for="(logo,index) in productIds" @click="goProDetail(logo.id)" :title="logo.name" ></div> </div></div>// 换行 <div v-vstop class="moreData" @mouseenter="showWin(index,'showindex')" @mouseleave="showindex=-1"> <i class="icon iconfont icon-left-arrow" v-show="showindex==index"> </i> <div v-for="(logo,index) in productIds" @click="goProDetail(logo.id)" :title="logo.name" ></div></div>我们应尽量保证代码清晰,按结构布局,如果代码密密麻麻,估计review的时候就会被打回来。并且严重影响阅读速度。1.1.3. 命名变量对象、类常量函数布尔值私有属性小驼峰大驼峰大写小驼峰小驼峰小驼峰区分单复数单数 动词开头is has can 肯定_ 下划线开头myName='' colleagues=['', ''] names =[]class DogHouseMAX_WIDTHcreateUser deleteUseravailable hasUser showName_sum()避免无意义变量名避免冲突全局存储多用肯定词不对外暴露1.2 精简应该尽可能让代码精简,越少的代码犯错的概率越低。维护和迭代成本也越低。 ...

June 24, 2019 · 1 min · jiezi