教师端H5埋点的现状与改进

        数据很重要。用户的行为数据就好比给了我们一双天眼,清晰的观察用户的习惯和需求,同时也能从中看出我们自己产品设计和经营中的一些不合理存在。大数据时代背景下,海量数据喷涌而出,“数据收集——数据整理——数据分析——数据可视化”,势在必行。
        数据第一步:数据收集。实现方式: 埋点。
教师端埋点现状
        提前封装好js片段,当需要统计的行为发生时,触发脚本执行,发送统计信息。
教师端埋点–每个页面统一的配置信息 和 页面统一入口 http://note.youdao.com/noteshare?id=f65209f833f444fbeb06b8a872c56928&sub=9C87991238584D7FA1C54461952DB75F
        教师端埋点–某些页面需要特殊配置的地方,就行单独处理 http://note.youdao.com/noteshare?id=cf762255544e27dc23f5a0a3a6fd7225&sub=96734D456CEA4F208DBF095E7E001EA0
        教师端埋点–stat.js(发送统计信息的方法和一些逻辑处理)http://note.youdao.com/noteshare?id=ae7ae2a06d973e173a294eb38fa34153&sub=3F5F4ECCE54149CB84FF8E825C0D9A7A
        大部分信息在大部分场景是通过统一配置和相应的过滤、映射等方式获取,个别除外。信息部分:进入首页的方式(refer)必须从客户端插件获取,共有登陆,启屏,开机视频,修改密码4种,这个只有客户端自己清楚,而H5只有通过调用原生插件,才能获取到。场景部分:某个按钮的点击(去分享按钮),tab的切换(首页底边栏4个,班级详情顶部栏3个),这些目前是手动触发的,可以参考第二个链接中的代码。
教师端埋点改进
        H5在埋点方面已经实现一定程度上的自动化,统一的配置、统一的入口拦截和发送。又或者当我们又增加了新的页面时,只需在views里做统一配置,然后去stat.js里面作统一映射,就可以了。但是,有些事臣妾做不到。比如IOS的事件有统一管理栈,可以作统一拦截和处理,但H5并没有这样机制,H5只能自己去做标识,再去跟自己自己做的标识作相应的监听处理,它跟我们的需求数据(即收集的数据)有莫大的关联,只能根据BI小组的需求去做相应的特殊处理。这种方式已经在PC的埋点中有一定的实践和应用,确实在一定程度上减少了前端的工作量和以后扩展的成本,这个也可以应用到教师端,作为改进部分方案,可在一定程度上解决“大部分场景”的问题,实现可配置的自动化,当然,相应的js脚本也得跟着变化,需求去执行监听和处罚的操作。
        这些优化只能算是局部优化,离完全自动化的埋点还有很大差距,欢迎老司机们献计献策~
        随着公司的发展壮大,对数据的需求会变化,之前很多额埋点信息会作废,推倒重新来埋不是不可能,为了面对这种情况,埋点的可扩展,可更改,高效率的实现方式很重要,一劳永逸永远是代码的最高境界。但,我们在寻求这个方式的前提下,不得不去考虑
        1、数据的准确性;
        2、性能。
        数据的全面、及时很重要,但数据的准确、可靠才是其价值的根基。
        扯这段没别的意思,只是想提醒一下,所有的埋点的解决方案都必须以数据的准确可靠作为基础。

爱学习前端代码规范v0.1

  • 基础配置:

编辑器请采用:vscode 下载链接:https://code.visualstudio.com/

设置代码缩进为2,采用空格缩进:”editor.tabSize”: 2

  • 文件名命名:

文件(文件夹)名单词间隔用“-”隔开,不要采用大小写(因为windows git不识别大小写)

例如:item-scroll.jsx、inner-top.vue、class-list/

  • 文件目录说明:

components/ 基础组件存放位置,*说明:基础组件一定不要携带任何业务及上下文,比如在button中写死了某个文案,就是携带业务

modules/ 基础模块存放位置,*说明:与基础组件一致,有多个基础组件组成

assets/ 静态文件存放目录

utils/ 公共函数库

pages/ 页面存放目录,*说明:每个大的页面尽量拆分子模块,子模块存放到自己页面的文件夹下,例如:pages/index/top.vue、pages/index/body.vue、pages/index/.vue

  • 代码规范(eslint配置):
“no-unused-vars”: “off”, // 关闭未使用变量检测
“no-console”: “off”, // 关闭使用console检测
“no-undef”: “off”, // 关闭未定义变量检测
“no-unreachable”: “off”, // 关闭强制返回检测
“no-constant-condition”: “off”, // 关闭判断条件中的常量检测
“semi”: “off”, // 关闭分号检测
“no-multi-spaces”: 1, // 不能有多余的空格
“curly”: [2, “all”], // 必须使用 if(){} 中的{}
“comma-dangle”: [“error”, “only-multiline”], // 允许对象末尾逗号,也可不写
“comma-spacing”: [“error”, { “before”: false, “after”: true }], // 逗号后面必须带空格
/**
* 对象空格限制 正确的例子
* var obj = { “foo”: 42 }
*/
“key-spacing”: [
  “error”, { “beforeColon”: false, “afterColon”: true, “mode”: “strict” }
],
/**
* 函数定义风格
    function foo() {
    }
    var bar = function () {
    }
    class Foo {
      constructor() {
      }
    }
    var foo = {
      bar() {
      }
    }
*/
“space-before-function-paren”: [
  “error”, {“anonymous”: “always”, “named”: “never”}
],
// 缩进必须用tab缩进 两个空格一个缩进
“indent”: [2, 2, { “SwitchCase”: 1 }],
// 不要写分号,除非自执行函数
“semi”: [“error”, “never”],
// 操作符前后在空格
“space-infix-ops”: “error”,
// 关键字后必须带空格
“space-after-keywords”: [“error”],
// 关键字前不能带空格
“space-before-keywords”: [“error”, “never”]

代码示例

基础组件示例:
DB5788DA-3AD6-4306-B6C9-752EC425E47C
DB5788DA-3AD6-4306-B6C9-752EC425E47C
68A218B7-B57A-4BEA-B0C0-5E878DF5889E
具体页面代码示例:
64EDC79B-A1D5-4183-9F34-94DD41C9DC76
业务页面具体实例:
2E4DEB19-A917-414B-954A-F2614A859D2F
方法名定义
所有绑定事件类的方法统一前缀 on 例如:onOpen、onMessage
所有后端拉取数据的方法统一前缀 get 例如:getList、getStudentDetail、保存统一前缀save、更新统一前缀update、删除统一前缀delete
所有内部私有方法统一前缀 _ 例如:_compareTime、_isStudent

2017前端发展趋势

回顾2016年前端市场,可谓如火如荼。各种前端的框架/库层出不穷,给大家带来方便的同时,也使得前端开发人员面临更多的学习成本。

2017年的前端会有怎样的变化呢?

一、微信小程序

微信小程序

微信小程序是一种可以媲美原生app的“app”,上市当天便在业内引起较大轰动。其实早在小程序之前也有百度轻应用这样的产品,很遗憾并未做起来。

究竟小程序会爆发多大的威力,我们拭目以待。但是可以肯定的是,一定会催生大量的小程序开发人员。而小程序用到的开发语言,就是我们前端的Java。相对于其他开发人员,这也是前端开发的一波红利。

二、Vue.js

Vue.js

是一个构建数据驱动的 web 界面的渐进式MVVM框架。Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。它只聚焦视图层,是一个构建数据驱动的Web界面的库。通过简单的API(应用程序编程接口)提供高效的数据绑定和灵活的组件系统。

它有如下优点:

1.轻量级的框架

2.双向数据绑定

3.指令

4.插件化

作为一个国产框架,又做的如此优秀,这里强烈推荐大家学习使用该框架。

三、React

React

React 起源于 Facebook 的内部项目,因为该公司对市场上所有 Java MVC 框架,都不满意,就决定自己写一套,用来架设 Instagram 的网站。React 的设计思想极其独特,属于革命性创新,性能出众,代码逻辑却非常简单。所以,越来越多的人开始关注和使用,认为它可能是将来 Web 开发的主流工具。

和Vue有点类似,React采用特殊的JSX语法,Vue.js在组件开发中也推崇编写.vue特殊文件格式,对文件内容都有一些约定,两者都需要编译后使用。

区别于Vue.js使用的是DOM模板,而React依赖Virtual DOM。React采用的Virtual DOM会对渲染出来的结果做脏检查。

四、es6

es6

ECMA 6.0(简称ES6)是Java语言的下一代标准,已经在2015年6月正式发布了。它的目标,是使得Java语言可以用来编写复杂的大型应用程序,成为企业级开发语言。相对于es5它有如下特点:

  • 箭头函数
  • 字符串
  • 解构
  • 模块
  • 参数

等等重大变革……

你可以简单理解es6相对于es5,犹如css2.0相对于css3.0。虽然es6还不能做到所有浏览器都支持,但这或许也不影响你开始学习它。

五、支付宝小程序

支付宝小程序

无独有偶,支付宝也将推出小程序(其实其团队内部已经好几个产品是基于支付宝小程序开发的了)。如果说微信小程序能够让前端翻了天,那我们也相信支付宝小程序也会是一股强大的力量。让我们持续关注吧。

六、Electron

Electron

Electron 提供了一个实时构建桌面应用的纯 Java 环境。简单来说,你可以使用Electron 来写一个桌面程序。比如:一个可以运行在windows上的百度云软件。

ES7初步 Async/Await 之于异步编程

在前端的业务中经常出现一种场景:我们先执行promise1,然后根据返回值,作为参数传入promise2,之后再根据这两个Promises得值,执行promise3。

如果使用Promise

const makeRequest = () => {
return promise1()
.then(value1 => {
// do something
return promise2(value1)
.then(value2 => {
// do something
return promise3(value1, value2)
})
})
}

Promise.all可以来避免很深的嵌套。

const makeRequest = () => {
return promise1()
.then(value1 => {
// do something
return Promise.all([value1, promise2(value1)])
})
.then(([value1, value2]) => {
// do something
return promise3(value1, value2)
})
}

使用async/await会非常简单:

const makeRequest = async () => {
const value1 = await promise1()
const value2 = await promise2(value1)
return promise3(value1, value2)
}

async 函数的用法:

async 函数返回一个 Promise 对象,可以使用 then 方法添加回调函数。当函数执行的时候,一旦遇到 await 就会先返回,等到触发的异步操作完成,再接着执行函数体内后面的语句。下面的例子,指定多少毫秒后输出一个值。

function timeout(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}

async function asyncPrint(value, ms) {
await timeout(ms);
console.log(value)
}

asyncPrint(‘hello world’, 50);

上面代码指定50毫秒以后,输出”hello world”。

如果希望多个请求并发执行,可以使用 Promise.all 方法:

async function dbFuc(db) {
let docs = [{}, {}, {}];
let promises = docs.map((doc) => db.post(doc));

let results = [];
for (let promise of promises) {
results.push(await promise);
}
console.log(results);
}
还有些注意的地方: await 命令只能用在 async 函数之中,如果用在普通函数,就会报错。

Electron – 创建跨平台的桌面客户的应用程序

Electron – 创建跨平台的桌面客户的应用程序
Electron 框架的前身是 Atom Shell,可以让你写使用 JavaScript,HTML 和 CSS 构建跨平台的桌面应用程序。它是基于io.js 和 Chromium 开源项目,并用于在 Atom 编辑器中。Electron 是开源的,由 GitHub 维护,有一个活跃的社区。最重要的是,Electron 应用服务构建和运行在 Mac,Windows 和 Linux。
Electron 结合了 Chromium、Node.js 和用于调用操作系统本地功能的 API(如打开文件窗口、通知、图标等)。
![title](https://leanote.com/api/file/getImage?fileId=58f4ce1aab64415134004063)

开发体验如何?
基于 Electron 的开发,就好像开发一个网页一样,而且能够无缝地 使用 Node。或者说:就好像构建一个 Node app,并通过 HTML 和 CSS 构建界面。另外,你只需为一个浏览器(最新的 Chrome)进行设计。

如何运用Electron开发桌面应用?

Electron是一个通过node服务搭建web的app。
Electron中的app模块主宰着这个应用的生命周期,创建可视window窗口需要等app模块确认准备就绪。
BrowserWindow模块 控制着可视窗口的创建,所有被创建出的窗口都是BrowserWindow模块的 new BrowserWindow(WINDOW_BOUNDS)方法来实例化的,通过实例的方法loadURL(HTML_URL)方法来加载要渲染的页面。这样一个简单的桌面应用便生成了。
简例如下:

app.on(‘ready’, () => {
let mainWindow = new BrowserWindow(win_para);
mainWindow.loadURL(config.mainUrl);
mainWindow.on(‘closed’, () => {
mainWindow = null;
app.quit()
});
mainWindow.on(‘ready-to-show’, () => {
mainWindow.show()
mainWindow.focus()
});
return mainWindow;
});

Electron 的进程:
Electron 有两种进程:主进程和渲染进程。有些模块会工作在其中一个进程上,而有些会在两个进程之上。主进程多地充当幕后角色,而渲染进程则是应用的每个窗口(window)。因为爱学习授课客户端的需求,所以目前的桌面应用暂时应用了一个主进程和一个渲染进程(后台进程,主要支持下载)
主进程:
主进程,通常通常是类似命名为main.js主文件所创建,该文件是每个 Electron 应用的入口。它控制了应用的生命周期(从打开到关闭)。它能调用原生元素和创建新的(多个)渲染进程,而且整个 Node API 是内置其中的。主进程中的IpcMain模块是与渲染进程通讯的主要手段
![title](https://leanote.com/api/file/getImage?fileId=58f4dac3ab64415134004173)
渲染进程:
渲染进程,可以是一个或多个创建出来的window模块,这些进程不被允许直接操控GUI,通常需要IpcRenderer模块与IpcMain模块进行通讯,也可以通过remote模块间接操控主进程,但是确实不提倡,也是不安全的。
![title](https://leanote.com/api/file/getImage?fileId=58f4daceab64414e1d004216)
简例:

/**
* 主进程 监听 自定义事件: 下载续传
*/
ipcMain.on(‘download-resume-hanlder’, (ipcResumeEvent, options) => {
if (_QUEUE.queueList[options].canResume()) {
_QUEUE.queueList[options].resume();
// 通讯事件通过sender.send(para)方法与渲染进程异步通讯
ipcResumeEvent.sender.send(‘download-has-resumed’, _QUEUE.queueList, _QUEUE.queueList.length);
} else {
IpcResumeEvent.sender.send(‘download-has-destroyed’);
}
});
/**
* 渲染进程 监听 自定义事件: 下载续传
*/
ipcRenderer.on(‘download-has-resumed’, (ipcResumeEvent, fileQueue, times) => {
//code to operate js
});
/**
* 渲染进程 发射 自定义事件: ‘download-has-paused’
*/
ipcRenderer.send(‘download-has-paused’, msg);

![title](https://leanote.com/api/file/getImage?fileId=58f4e25cab644151340041f4)

模块:
Electron 的 API 是根据它们的功能进行分组。例如:dialog 模块拥有所有原生 dialog 的 API,如打开文件、保存文件和弹窗。
授课客户端暂时用到的模块主要如下:
app, browserWinodw, ipcMain, ipcRender, remote, dialog, session, webContents, shell, fs, path。
app 模块是为了控制整个应用的生命周期设计的。
BrowserWindow 模块让你有创建一个浏览器窗口的权力。
ipcMain 模块是类 EventEmitter 的实例.当在主进程中使用它的时候,它控制着由渲染进程(web page)发送过来的异步或同步消息.从渲染进程发送过来的消息将触发事件。
ipcRenderer 模块是一个 EventEmitter 类的实例. 它提供了有限的方法,你可以从渲染进程向主进程发送同步或异步消息。 也可以收到主进程的响应。
remote 模块提供了一种在渲染进程(网页)和主进程之间进行进程间通讯(IPC)的简便途径。
dialog 模块提供了api来展示原生的系统对话框,例如打开文件框,alert框,所以web应用可以给用户带来跟系统应用相同的体验。
session 模块可以用来创建一个新的 Session 对象。主要应用于下载。
webContents 是一个 事件发出者。它负责渲染并控制网页,也是 BrowserWindow 对象的属性。
shell 模块提供了集成其他桌面客户端的关联功能。
fs 模块主要是文件读写,本地文件系统操作。
path 模块主要是文件在系统中的路径。

Electron使用一个 package.json 文件。该文件能定义哪个文件作为主进程,并因此让 Electron 知道从何启动你的应用。然后主进程能创建渲染进程,并能使用 IPC 让两者间进行消息传递。
![title](https://leanote.com/api/file/getImage?fileId=58f4e289ab644151340041f6)

以上是关于Elertron这个APP的简短介绍。下面是客户端的Two-Package Structure,及APP Package等方面的简介。

Two-Package Structure:

Two-Package Structure 是 pack 工具 electron-builder 给的约定,也是目前业界用的较多的方案。

![Two-Package Structure](https://leanote.com/api/file/getImage?fileId=58f4e9e7ab64415134004267)

为啥用 Two-Package Structure?

最大的好处是可以很好地分离开发依赖和生成环境依赖。开发依赖存 package.json ,生产依赖存 app/package.json ,这样在 pack 后交付给用户时就不会包含 webpack, mocha 等等的开发依赖了。

Electron 应用的打包

Electron 应用的打包 是应用了脚手架 electron-packager。首先将项目文件打包,然后应用electron-packager来打包electron应用.
可以用命令打包一个供windows使用的app: electron-packager ./app aixuexi –platform=win32 –arch=x64 –out=./dist –asar true –overwrite “,
也可以自行添加文件配置electron的打包参数 如:

building: {
‘app-version’: appPackage.version,
arch: [‘x64’, ‘ia32’], ia32, x64, armv7l, all
asar: false,
dir: path.join(__dirname, ‘/app’),
icon: path.join(__dirname, ‘app/icons/icon’),
ignore: /src|main.ejs|icons/,
out: path.join(__dirname, ‘/app/dist’),
overwrite: true,
platform: process.env.PLATFORM_TARGET || ‘all’,
name: appPackage.product
}

待续…

html2canvas的那些事:如何生成高清canvas图片

前几天产品提出一个问题,教师端app绘制出的用于微信分享的排行榜图片像素比较差,部分老师不愿意分享。针对这个问题,我去尝试做了一些优化。

方案一:
原理如下:先画个2倍的所谓的渣像素的图片,然后缩小2倍显示。
代码如下:(最终生成base64)

        getBase64 (ref) {
             returnnewPromise ((resolve) => {
                   setTimeout(() =>{
                           var _canvas = document.createElement(“canvas”),
                                  w = ref.offsetWidth,
                                  h = ref.offsetHeight;
                           _canvas.width = w * 2;
                           _canvas.height = h * 2;
                           _canvas.style.width = w + “px”;
                           _canvas.style.height = h + “px”;
                           var context = _canvas.getContext(“2d”);
                           //然后将画布缩放,将图像放大两倍画到画布上
                           context.scale(2,2);
                           html2Canvas(ref, {
                                canvas: _canvas,
                                onrendered: (canvas) => {
                                       resolve(canvas.toDataURL(“image/png”));
                                }
                           });
                    });
               });
           }
但是遇到一个问题:部分安卓手机,比如华为P9,会崩掉,猜测是Hbuiler打开webview的内存限制,而oppo R9就可以绘制出高清的图片。由于不能适配所有手机,故没有采用这种方案。
方案二:

如果保存为JPEG图片,还可以通过第二个参数指定图片质量:

var imgsrc = myCanvas.toDataURL('image/jpeg', quality);

quality的取值范围为0.0-1.0,0.0代表图片质量最差,1.0代表图片质量最好。

但是,此方案需要客户端修改截取base64数据的位数,即客户端需要更新,暂时放弃此法,可作为以后参考用。

目前,优化搁浅,尚未找到合适的方案。后面我会尝试确认方案一中手机崩掉的具体原因,并尝试解决。网上很多人都是通过该方法解决canvas绘制图片的清晰度的问题的,证明此法应该是行得通的,可能是自己哪里配置/写法有问题。

如有好的意见或者方法,欢迎提出来。我也会持续跟进更新这个问题。。。

iOS 三方框架管理工具 – CocoaPods

CocoaPods是什么?

CocoaPods是一个用来帮助我们管理第三方依赖库的工具。它可以解决库与库之间的依赖关系,下载库的源代码,同时通过创建一个Xcode的workspace来将这些第三方库和我们的工程连接起来,供我们开发使用。

使用CocoaPods的目的是让我们能自动化的、集中的、直观的管理第三方开源库。

为什么使用CocoaPods?

1.引用知名公司三方框架时,如:微信,weex,高德等。这些公司提供的三方框架更新比较频繁,如果不适用CocoaPods,那么对于后期的维护迭代非常不利。

举个例子:教师端APP现在APP没有CocoaPods,使用下载SDK的方式来集成,后期如果微信对于一些分享进行修改,我就需要重新下载新的SDK然后重新集成。

2.引用主流三方框架时,如:AFN,SDWebimage等,这些git的优秀框架,全球的iOS开发者都在使用和给出改进建议,更新比较频繁,尤其遇到重大更新时,会对于老版本的SDK进行API的修改,对于后期的维护也是非常不利的。

再举个例子:教师端APP之前使用的AFN的2.5.1版本(现在都已经是3.0+的版本的),与最新的版本中的方法无法平稳过度使用,因为在2.8左右时,AFN使用了苹果提供的新的网络框架,所以现在APP中的网络框架有的一些缺陷只能在缺陷上想办法弥补, 而不是更新下框架就可以解决的。

3.引用的三方框架有依赖时,iOS中的一些三方框架中对于另外的三方框架有依赖关系,如果不用CocoaPods,那么就需要把用到的三方框架以及它的依赖三方都下载集成进来,麻烦而且浪费。但是使用CocoaPods的话,CocoaPods会自动帮我们处理这些问题,我们只要告诉CocoaPods我要用哪个框架就好了。