微信应用号-小程序

为了让大家尽快看到这份教程,博卡君注定要熬夜了!今晚开始更新,希望明天一早就能发布第一篇教程!记录开始!看看几天能完成变身吧!

序言

开始开发应用号之前,先看看官方公布的「小程序」教程吧!(以下内容来自微信官方公布的「小程序」开发指南)

本文档将带你一步步创建完成一个微信小程序,并可以在手机上体验该小程序的实际效果。这个小程序的首页将会显示欢迎语以及当前用户的微信头像,点击头像,可以在新开的页面中查看当前小程序的启动日志。

  1. 获取微信小程序的 AppID

首先,我们需要拥有一个帐号,如果你能看到该文档,我们应当已经邀请并为你创建好一个帐号。注意不可直接使用服务号或订阅号的 AppID。 利用提供的帐号,登录 https://mp.weixin.qq.com ,就可以在网站的「设置」-「开发者设置」中,查看到微信小程序的 AppID 了。

注意:如果我们不是用注册时绑定的管理员微信号,在手机上体验该小程序。那么我们还需要操作「绑定开发者」。即在「用户身份 - 开发者」模块,绑定上需要体验该小程序的微信号。本教程默认注册帐号、体验都是使用管理员微信号。

  1. 创建项目

我们需要通过开发者工具,来完成小程序创建和代码编辑。

开发者工具安装完成后,打开并使用微信扫码登录。选择创建「项目」,填入上文获取到的 AppID,设置一个本地项目的名称(非小程序名称),比如「我的第一个项目」,并选择一个本地的文件夹作为代码存储的目录,点击「新建项目」就可以了。

为方便初学者了解微信小程序的基本代码结构,在创建过程中,如果选择的本地文件夹是个空文件夹,开发者工具会提示,是否需要创建一个 quick start 项目。选择「是」,开发者工具会帮助我们在开发目录里生成一个简单的 demo。

项目创建成功后,我们就可以点击该项目,进入并看到完整的开发者工具界面,点击左侧导航,在「编辑」里可以查看和编辑我们的代码,在「调试」里可以测试代码并模拟小程序在微信客户端效果,在「项目」里可以发送到手机里预览实际效果。

  1. 编写代码

点击开发者工具左侧导航的「编辑」,我们可以看到这个项目,已经初始化并包含了一些简单的代码文件。最关键也是必不可少的,是 app.js、app.json、app.wxss 这三个。其中,.js 后缀的是脚本文件,.json 后缀的文件是配置文件,.wxss 后缀的是样式表文件。微信小程序会读取这些文件,并生成小程序实例。

下面我们简单了解这三个文件的功能,方便修改以及从头开发自己的微信小程序。

app.js 是小程序的脚本代码。我们可以在这个文件中监听并处理小程序的生命周期函数、声明全局变量。调用 MINA 提供的丰富的 API,如本例的同步存储及同步读取本地数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
//app.js

App({

onLaunch: function () {

// 调用 API 从本地缓存中获取数据

var logs = wx.getStorageSync('logs') || []

logs.unshift(Date.now())

wx.setStorageSync('logs', logs)

},

getUserInfo:function(cb){

var that = this;

if(this.globalData.userInfo){

typeof cb == "function" && cb(this.globalData.userInfo)

}else{



// 调用登录接口

wx.login({

success: function () {

wx.getUserInfo({

success: function (res) {

that.globalData.userInfo = res.userInfo;

typeof cb == "function" && cb(that.globalData.userInfo)

}

})

}

});

}

},

globalData:{

userInfo:null

}

})

app.json 是对整个小程序的全局配置。我们可以在这个文件中配置小程序是由哪些页面组成,配置小程序的窗口 背景色,配置导航条样式,配置默认标题。注意该文件不可添加任何注释。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**app.json*/
{

"pages":[

"pages/index/index",

"pages/logs/logs"

],

"window":{

"backgroundTextStyle":"light",

"navigationBarBackgroundColor": "#fff",

"navigationBarTitleText": "WeChat",

"navigationBarTextStyle":"black"

}

}

app.wxss 是整个小程序的公共样式表。我们可以在页面组件的 class 属性上直接使用 app.wxss 中声明的样式规则。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**app.wxss**/

.container {

height: 100%;

display: flex;

flex-direction: column;

align-items: center;

justify-content: space-between;

padding: 200rpx 0;

box-sizing: border-box;

}

  1. 创建页面

在这个教程里,我们有两个页面,index 页面和 logs 页面,即欢迎页和小程序启动日志的展示页,他们都在 pages 目录下。微信小程序中的每一个页面的【路径 + 页面名】都需要写在 app.json 的 pages 中,且 pages 中的第一个页面是小程序的首页。

每一个小程序页面是由同路径下同名的四个不同后缀文件的组成,如:index.js、index.wxml、index.wxss、index.json。.js 后缀的文件是脚本文件,.json 后缀的文件是配置文件,.wxss 后缀的是样式表文件,.wxml 后缀的文件是页面结构文件。

index.wxml 是页面的结构文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!--index.wxml-->

<view class="container">

<view bindtap="bindViewTap" class="userinfo">

<image class="userinfo-avatar" src="{{userInfo.avatarUrl}}" background-size="cover"></image>

<text class="userinfo-nickname">{{userInfo.nickName}}</text>

</view>

<view class="usermotto">

<text class="user-motto">{{motto}}</text>

</view>

</view>

本例中使用了 来搭建页面结构,绑定数据和交互处理函数。

index.js 是页面的脚本文件,在这个文件中我们可以监听并处理页面的生命周期函数、获取小程序实例,声明并处理数据,响应页面交互事件等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
//index.js

// 获取应用实例

var app = getApp()

Page({

data: {

motto: 'Hello World',

userInfo: {}

},

// 事件处理函数

bindViewTap: function() {

wx.navigateTo({

url: '../logs/logs'

})

},

onLoad: function () {

console.log('onLoad')

var that = this

// 调用应用实例的方法获取全局数据

app.getUserInfo(function(userInfo){

// 更新数据

that.setData({

userInfo:userInfo

})

})

}

})
index.wxss 是页面的样式表:

/**index.wxss**/

.userinfo {

display: flex;

flex-direction: column;

align-items: center;

}



.userinfo-avatar {

width: 128rpx;

height: 128rpx;

margin: 20rpx;

border-radius: 50%;

}



.userinfo-nickname {

color: #aaa;

}



.usermotto {

margin-top: 200px;

}

页面的样式表是非必要的。当有页面样式表时,页面的样式表中的样式规则会层叠覆盖 app.wxss 中的样式规则。如果不指定页面的样式表,也可以在页面的结构文件中直接使用 app.wxss 中指定的样式规则。

index.json 是页面的配置文件:

页面的配置文件是非必要的。当有页面的配置文件时,配置项在该页面会覆盖 app.json 的 window 中相同的配置项。如果没有指定的页面配置文件,则在该页面直接使用 app.json 中的默认配置。

logs 的页面结构

1
2
3
4
5
6
7
8
9
10
11
<!--logs.wxml-->

<view class="container log-list">

<block wx:for-items="{{logs}}" wx:for-item="log">

<text class="log-item">{{index + 1}}. {{log}}</text>

</block>

</view>

logs 页面使用 控制标签来组织代码,在 上使用 wx:for-items 绑定 logs 数据,并将 logs 数据循环展开节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//logs.js

var util = require('../../utils/util.js')

Page({

data: {

logs: []

},

onLoad: function () {

this.setData({

logs: (wx.getStorageSync('logs') || []).map(function (log) {

return util.formatTime(new Date(log))

})

})

}

})

运行结果如下:

  1. 手机预览

开发者工具左侧菜单栏选择「项目」,点击「预览」,扫码后即可在微信客户端中体验。

目前,预览和上传功能尚无法实现,需要等待微信官方的下一步更新。

如你所见,微信官方给出的开发指南还非常简单,很多细节、代码和功能都没有明确的展示,所以接下来就到博卡君展示实力的时候啦!开发教程正式开始!

第一章:准备工作

做好准备工作很重要。开发一个微信应用号,你需要提前到微信的官方网站(weixin.qq.com)下载开发者工具。

  1. 下载最新微信开发者工具,打开后你会看到该界面:
  1. 点击「新建 web+」项目,随后出现如下画面:
  1. 该页面内的各项内容需要注意——

AppID:依照官方解释来填。
Appname: 项目最外层文件夹名称,如你将其命名为「ABC」,则之后的全部项目内容均将保存在「/ABC/…」目录下。
本地开发目录:项目存放在本地的目录。
注:再次强调,如果你和团队成员共同开发该项目,则建议你们使用同样的目录名称及本地目录,以确保协同开发的统一性。如果你之前已有项目,则导入过程与以上内容近似,不再赘述。

  1. 准备工作全部完成后,点击「新建项目」按钮,弹出框点「确定」。
  1. 如上图所示,此刻,微信开发者工具已经为你自动构建了一个初始的 demo 项目,该项目内包含了一个微信应用项目所需具备的基本内容和框架结构。点击项目名称(图中即「cards」)进入该项目,就能看到整个项目的基本架构了:

第二章:项目构架

微信目前用户群体非常庞大,微信推出公众号以后,火爆程度大家都看得到,也同样推动着 h5 的高速发展,随着公众号业务的需求越来越复杂,应用号现在的到来也是恰到好处。我们团队具体看了一两次文档后发现,它提供给开发者的方式也在发生全面的改变,从操作 DOM 转为操作数据,基于微信提供的一个过桥工具实现很多 h5 在公众号很难实现的功能,有点类似于 hybrid 开发,不同于 hybrid 开发的方式是:微信开放的接口更为严谨,结构必须采用他提供给我们的组件,外部的框架和插件都不能在这里使用上,让开发者完全脱离操作 DOM,开发思想转变很大。

工欲善其事,必先利其器。理解它的核心功能非常重要,先了解它的整个运作流程。

生命周期:

在index.js里面:

开发者工具上 Console 可以看到:

在首页 console 可以看出顺序是 App Launch–>App Show–>onload–>onShow–>onReady。

首先是整个 app 的启动与显示,app 的启动在 app.js 里面可以配置,其次再进入到各个页面的加载显示等等。

可以想象到这里可以处理很多东西了,如加载框之类的都可以实现等等。

路由:

路由在项目开发中一直是个核心点,在这里其实微信对路由的介绍很少,可见微信在路由方面经过很好的封装,也提供三个跳转方法。

wx.navigateTo(OBJECT):保留当前页面,跳转到应用内的某个页面,使用wx.navigateBack可以返回到原页面。

wx.redirectTo(OBJECT):关闭当前页面,跳转到应用内的某个页面。

wx.navigateBack():关闭当前页面,回退前一页面。

这三个基本上使用足够,在路由方面微信封装的很好,开发者根本不用去配置路由,往往很多框架在路由方面配置很繁琐。

组件:

此次微信在组件提供方面也是非常全面,基本上满足项目需求,故而开发速度非常快,开发前可以认真浏览几次,开发效率会很好。

其它:

任何外部框架以及插件基本上无法使用,就算原生的 js 插件也很难使用,因为以前我们的 js 插件也基本上全部是一操作 dom 的形式存在,而微信应用号此次的架构是不允许操作任何 dom,就连以前我们习惯使用的动态设置的rem.js也是不支持的。

此次微信还提供了 WebSocket,就可以直接利用它做聊天,可以开发的空间非常大。

跟公众号对比我们发现,开发应用号组件化,结构化,多样化。新大陆总是充满着惊喜,更多的彩蛋等着大家来发现。

接下来开始搞一些简单的代码了!

  1. 找到项目文件夹,导入你的编辑器里面。在这里,我使用了 Sublime Text 编辑器。你可以根据自己的开发习惯选择自己喜欢的编辑器。
  1. 接下来,你需要根据自己的项目内容调整项目结构。在范例项目中,「card_course」目录下面主要包含了「tabBar」页面以及该应用的一些配置文件。

  2. 示例项目的「tabBar」是五个菜单按钮:

  1. 找到「app.json」文件,用来配置这个五个菜单。在代码行中找到「”tabBar”」:

你可以根据实际项目需求更改,其中:

「Color」是底部字体颜色,「selectedColor」是切换到该页面高亮颜色,「borderStyle」是切换菜单上面的一条线的颜色,「backgroundColor」是底部菜单栏背景颜色。文字描述较为抽象,建议你一一调试并查看其效果,加深印象。
「“list”」下的代码顺序必须依次放置,不能随便更改。
「”pagePath”」之后的文件名内,「.wxml」后缀被隐藏起来了,这是微信开发代码中人性化的一点——帮你节约写代码的时间,无须频繁声明文件后缀。
「”iconPath”」为未获得显示页面的图标路径,这两个路径可以直接是网络图标。
「”selectedIconPath”」为当前显示页面高亮图标路径,可以去掉,去掉之后会默认显示为「”iconPath”」的图标。
「”Text”」为页面标题,也可以去掉,去掉之后纯显示图标,如只去掉其中一个,该位置会被占用。
注意:微信的底部菜单最多支持五栏(五个 icons),所以在你设计微信应用的 UI 和基本架构时就要预先考虑好菜单栏的排布。

  1. 根据以上代码规则,我做好了示例项目的基本架构,供你参考:
  1. 「Json」文件配置好后,「card_course」的基本结构入上图所示,不需要的子集都可以暂时删除,缺少的子集则需要你主动新建。删除子集时记得顺带检查一下「app.json」里的相关内容是否已经一并删除。

注意:我个人建议你新建一个「wxml」文件的同时,把对应的「js」和「wxss」文件一起新建好,因为微信应用号的配置特点就是解析到一个「wxml」文件时,会同时在同级目录下找到同文件名的「js」和「wxss」文件,所以「js」文件需及时在「app.json」里预先配置好。

编写「wxml」时,根据微信应用号提供的接口编码即可,大部分就是以前的「div」,而我们现在就用「view」即可。需要用其它子集时,可以根据微信提供的接口酌情选择。

使用「class」名来设置样式,「id」名在这里基本没有什么用处。主要操作数据,不操作「dom」。

  1. 以上是示例项目首页的「wxml」编码。从图中就可以看出,实现一个页面代码量非常少。

  2. 「Wxss」文件是引入的样式文件,你也可以直接在里面写样式,示例中采用的是引入方式:

  1. 修改代码后刷新一次,可以看到未设背景的「view」标签直接变成了粉色。

注意:修改「wxml」和「wxss」下的内容后,直接 F5 刷新就能直接看到效果,修改「js」则需点击重启按钮才能看到效果。

  1. 另外,公共样式可以在「app.wxss」里直接引用。
  1. 「Js」文件需要在「app.json」文件的「”page”」里预先配置好。为了项目结构清晰化,我在示例项目中的「index」首页同级目录新建其它四个页面文件,具体如下:

经过以上步骤,案例中的五个底部菜单就全部配置完毕了。

转贴自:https://my.oschina.net/wwnick/blog/750055
原作者:博卡君

Top

2016年9月1日新广告法,互联网新广告法,新广告法,百度竞价整理办法

**国家工商行政管理总局令
第87号

  《互联网广告管理暂行办法》已经国家工商行政管理总局局务会议审议通过,现予公布,自2016年9月1日起施行。

  局长 张茅

  2016年7月4日

互联网广告管理暂行办法

(2016年7月4日国家工商行政管理总局令第87号公布)

  第一条 为了规范互联网广告活动,保护消费者的合法权益,促进互联网广告业的健康发展,维护公平竞争的市场经济秩序,根据《中华人民共和国广告法》(以下简称广告法)等法律、行政法规,制定本办法。

  第二条 利用互联网从事广告活动,适用广告法和本办法的规定。

  第三条 本办法所称互联网广告,是指通过网站、网页、互联网应用程序等互联网媒介,以文字、图片、音频、视频或者其他形式,直接或者间接地推销商品或者服务的商业广告。

  前款所称互联网广告包括:

  (一)推销商品或者服务的含有链接的文字、图片或者视频等形式的广告;

  (二)推销商品或者服务的电子邮件广告;

  (三)推销商品或者服务的付费搜索广告;

  (四)推销商品或者服务的商业性展示中的广告,法律、法规和规章规定经营者应当向消费者提供的信息的展示依照其规定;

  (五)其他通过互联网媒介推销商品或者服务的商业广告。

  第四条 鼓励和支持广告行业组织依照法律、法规、规章和章程的规定,制定行业规范,加强行业自律,促进行业发展,引导会员依法从事互联网广告活动,推动互联网广告行业诚信建设。

  第五条 法律、行政法规规定禁止生产、销售的商品或者提供的服务,以及禁止发布广告的商品或者服务,任何单位或者个人不得在互联网上设计、制作、代理、发布广告。

  禁止利用互联网发布处方药和烟草的广告。

  第六条 医疗、药品、特殊医学用途配方食品、医疗器械、农药、兽药、保健食品广告等法律、行政法规规定须经广告审查机关进行审查的特殊商品或者服务的广告,未经审查,不得发布。

  第七条 互联网广告应当具有可识别性,显著标明“广告”,使消费者能够辨明其为广告。

  付费搜索广告应当与自然搜索结果明显区分。

  第八条 利用互联网发布、发送广告,不得影响用户正常使用网络。在互联网页面以弹出等形式发布的广告,应当显著标明关闭标志,确保一键关闭。

  不得以欺骗方式诱使用户点击广告内容。

  未经允许,不得在用户发送的电子邮件中附加广告或者广告链接。

  第九条 互联网广告主、广告经营者、广告发布者之间在互联网广告活动中应当依法订立书面合同。

  第十条 互联网广告主应当对广告内容的真实性负责。

  广告主发布互联网广告需具备的主体身份、行政许可、引证内容等证明文件,应当真实、合法、有效。

  广告主可以通过自设网站或者拥有合法使用权的互联网媒介自行发布广告,也可以委托互联网广告经营者、广告发布者发布广告。

  互联网广告主委托互联网广告经营者、广告发布者发布广告,修改广告内容时,应当以书面形式或者其他可以被确认的方式通知为其提供服务的互联网广告经营者、广告发布者。

  第十一条 为广告主或者广告经营者推送或者展示互联网广告,并能够核对广告内容、决定广告发布的自然人、法人或者其他组织,是互联网广告的发布者。

  第十二条 互联网广告发布者、广告经营者应当按照国家有关规定建立、健全互联网广告业务的承接登记、审核、档案管理制度;审核查验并登记广告主的名称、地址和有效联系方式等主体身份信息,建立登记档案并定期核实更新。

  互联网广告发布者、广告经营者应当查验有关证明文件,核对广告内容,对内容不符或者证明文件不全的广告,不得设计、制作、代理、发布。

  互联网广告发布者、广告经营者应当配备熟悉广告法规的广告审查人员;有条件的还应当设立专门机构,负责互联网广告的审查。

  第十三条 互联网广告可以以程序化购买广告的方式,通过广告需求方平台、媒介方平台以及广告信息交换平台等所提供的信息整合、数据分析等服务进行有针对性地发布。

  通过程序化购买广告方式发布的互联网广告,广告需求方平台经营者应当清晰标明广告来源。

  第十四条 广告需求方平台是指整合广告主需求,为广告主提供发布服务的广告主服务平台。广告需求方平台的经营者是互联网广告发布者、广告经营者。

  媒介方平台是指整合媒介方资源,为媒介所有者或者管理者提供程序化的广告分配和筛选的媒介服务平台。

  广告信息交换平台是提供数据交换、分析匹配、交易结算等服务的数据处理平台。

  第十五条 广告需求方平台经营者、媒介方平台经营者、广告信息交换平台经营者以及媒介方平台的成员,在订立互联网广告合同时,应当查验合同相对方的主体身份证明文件、真实名称、地址和有效联系方式等信息,建立登记档案并定期核实更新。

  媒介方平台经营者、广告信息交换平台经营者以及媒介方平台成员,对其明知或者应知的违法广告,应当采取删除、屏蔽、断开链接等技术措施和管理措施,予以制止。

  第十六条 互联网广告活动中不得有下列行为:

  (一)提供或者利用应用程序、硬件等对他人正当经营的广告采取拦截、过滤、覆盖、快进等限制措施;

  (二)利用网络通路、网络设备、应用程序等破坏正常广告数据传输,篡改或者遮挡他人正当经营的广告,擅自加载广告;

  (三)利用虚假的统计数据、传播效果或者互联网媒介价值,诱导错误报价,谋取不正当利益或者损害他人利益。

  第十七条 未参与互联网广告经营活动,仅为互联网广告提供信息服务的互联网信息服务提供者,对其明知或者应知利用其信息服务发布违法广告的,应当予以制止。

  第十八条 对互联网广告违法行为实施行政处罚,由广告发布者所在地工商行政管理部门管辖。广告发布者所在地工商行政管理部门管辖异地广告主、广告经营者有困难的,可以将广告主、广告经营者的违法情况移交广告主、广告经营者所在地工商行政管理部门处理。

  广告主所在地、广告经营者所在地工商行政管理部门先行发现违法线索或者收到投诉、举报的,也可以进行管辖。

  对广告主自行发布的违法广告实施行政处罚,由广告主所在地工商行政管理部门管辖。

  第十九条 工商行政管理部门在查处违法广告时,可以行使下列职权:

  (一)对涉嫌从事违法广告活动的场所实施现场检查;

  (二)询问涉嫌违法的有关当事人,对有关单位或者个人进行调查;

  (三)要求涉嫌违法当事人限期提供有关证明文件;

  (四)查阅、复制与涉嫌违法广告有关的合同、票据、账簿、广告作品和互联网广告后台数据,采用截屏、页面另存、拍照等方法确认互联网广告内容;

  (五)责令暂停发布可能造成严重后果的涉嫌违法广告。

  工商行政管理部门依法行使前款规定的职权时,当事人应当协助、配合,不得拒绝、阻挠或者隐瞒真实情况。

  第二十条 工商行政管理部门对互联网广告的技术监测记录资料,可以作为对违法的互联网广告实施行政处罚或者采取行政措施的电子数据证据。

  第二十一条 违反本办法第五条第一款规定,利用互联网广告推销禁止生产、销售的产品或者提供的服务,或者禁止发布广告的商品或者服务的,依照广告法第五十七条第五项的规定予以处罚;违反第二款的规定,利用互联网发布处方药、烟草广告的,依照广告法第五十七条第二项、第四项的规定予以处罚。

  第二十二条 违反本办法第六条规定,未经审查发布广告的,依照广告法第五十八条第一款第十四项的规定予以处罚。

  第二十三条 互联网广告违反本办法第七条规定,不具有可识别性的,依照广告法第五十九条第三款的规定予以处罚。

  第二十四条 违反本办法第八条第一款规定,利用互联网发布广告,未显著标明关闭标志并确保一键关闭的,依照广告法第六十三条第二款的规定进行处罚;违反第二款、第三款规定,以欺骗方式诱使用户点击广告内容的,或者未经允许,在用户发送的电子邮件中附加广告或者广告链接的,责令改正,处一万元以上三万元以下的罚款。

  第二十五条 违反本办法第十二条第一款、第二款规定,互联网广告发布者、广告经营者未按照国家有关规定建立、健全广告业务管理制度的,或者未对广告内容进行核对的,依照广告法第六十一条第一款的规定予以处罚。

  第二十六条 有下列情形之一的,责令改正,处一万元以上三万元以下的罚款:

  (一)广告需求方平台经营者违反本办法第十三条第二款规定,通过程序化购买方式发布的广告未标明来源的;

  (二)媒介方平台经营者、广告信息交换平台经营者以及媒介方平台成员,违反本办法第十五条第一款、第二款规定,未履行相关义务的。

  第二十七条 违反本办法第十七条规定,互联网信息服务提供者明知或者应知互联网广告活动违法不予制止的,依照广告法第六十四条规定予以处罚。

  第二十八条 工商行政管理部门依照广告法和本办法规定所做出的行政处罚决定,应当通过企业信用信息公示系统依法向社会公示。

Top

HTML5 postMessage 和 onmessage API 详细应用

至 2008 年 W3C 制定出第一个 HTML5 草案开始,HTML5 承载了越来越多崭新的特性和功能。它不但强化了 Web 系统或网页的表现性能,而且还增加了对本地数据库等 Web 应用功能的支持。其中,最重要的一个便是对多线程的支持。在 HTML5 中提出了工作线程(Web Workers)的概念,并且规范出 Web Workers 的三大主要特征:能够长时间运行(响应),理想的启动性能以及理想的内存消耗。Web Workers 允许开发人员编写能够长时间运行而不被用户所中断的后台程序,去执行事务或者逻辑,并同时保证页面对用户的及时响应。
Web Workers 为 Web 前端网页上的脚本提供了一种能在后台进程中运行的方法。一旦它被创建,Web Workers 就可以通过 postMessage 向任务池发送任务请求,执行完之后再通过 postMessage 返回消息给创建者指定的事件处理程序 ( 通过 onmessage 进行捕获 )。Web Workers 进程能够在不影响用户界面的情况下处理任务,并且,它还可以使用 XMLHttpRequest 来处理 I/O,但通常,后台进程(包括 Web Workers 进程)不能对 DOM 进行操作。如果希望后台程序处理的结果能够改变 DOM,只能通过返回消息给创建者的回调函数进行处理。
浏览器对 HTML5 支持情况可以参考网站 When can I use…
在 Web Workers 中使用 postMessage 和 onmessage
首先,需要在客户端页面的 JavaScript 代码中 new 一个 Worker 实例出来,参数是需要在另一个线程中运行的 JavaScript 文件名称。然后在这个实例上监听 onmessage 事件。最后另一个线程中的 JavaScript 就可以通过调用 postMessage 方法在这两个线程间传递数据了。
清单 1. 主线程中创建 Worker 实例,并监听 onmessage 事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<html> 
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Test Web worker</title>
<script type="text/JavaScript">
function init(){
var worker = new Worker('compute.js');
//event 参数中有 data 属性,就是子线程中返回的结果数据
worker.onmessage= function (event) {
// 把子线程返回的结果添加到 div 上
document.getElementById("result").innerHTML +=
event.data+"<br/>";
};
}
</script>

</head>
<body onload="init()">
<div id="result"></div>
</body>
</html>

在客户端的 compute.js 中,只是简单的重复多次加和操作,最后通过 postMessage 方法把结果返回给主线程,目的就是等待一段时间。而在这段时间内,主线程不应该被阻塞,用户可以通过拖拽浏览器,变大缩小浏览器窗口等操作测试这一现象。这个非阻塞主线程的结果就是 Web Workers 想达到的目的。
清单 2. compute.js 中调用 postMessage 方法返回计算结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var i=0; 

function timedCount(){
for(var j=0,sum=0;j<100;j++){
for(var i=0;i<100000000;i++){
sum+=i;
}
}
// 调用 postMessage 向主线程发送消息
postMessage(sum);
}

postMessage("Before computing,"+new Date());
timedCount();
postMessage("After computing,"+new Date());

图 1. 浏览器中运行结果
浏览器中运行结果
Cross-document messaging
Cross-document messaging 简介
由于同源策略的限制,JavaScript 跨域的问题,一直是一个颇为棘手的问题。HTML5 提供了在网页文档之间互相接收与发送信息的功能。使用这个功能,只要获取到网页所在窗口对象的实例,不仅同源(域 + 端口号)的 Web 网页之间可以互相通信,甚至可以实现跨域通信。 要想接收从其他窗口发送来的信息,必须对窗口对象的 onmessage 事件进行监听,其它窗口可以通过 postMessage 方法来传递数据。该方法使用两个参数:第一个参数为所发送的消息文本,但也可以是任何 JavaScript 对象(通过 JSON 转换对象为文本),第二个参数为接收消息的对象窗口的 URL 地址,可以在 URL 地址字符串中使用通配符’*’指定全部地。
在 Cross-document messaging 中使用 postMessage 和 onmessage
为了实现不同域之间的通信,需要在操作系统的 hosts 文件添加两个域名,进行模拟。
清单 3. hosts 文件中添加两个不同的域名

1
2
127.0.0.1     parent.com 
127.0.0.1 child.com

在父网页中通过 iframe 嵌入子页面,并在 JavaScript 代码中调用 postMessage 方法发送数据到子窗口。
清单 4. 父页面中嵌入子页面,调用 postMessage 方法发送数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<html> 
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Test Cross-domain communication using HTML5</title>
<script type="text/JavaScript">
function sendIt(){
// 通过 postMessage 向子窗口发送数据
document.getElementById("otherPage").contentWindow
.postMessage(
document.getElementById("message").value,
"http://child.com:8080"
);
}
</script>

</head>
<body>
<!-- 通过 iframe 嵌入子页面 -->
<iframe src="http://child.com:8080/TestHTML5/other-domain.html"
id="otherPage"></iframe>

<br/><br/>
<input type="text" id="message"><input type="button"
value="Send to child.com" onclick="sendIt()" />

</body>
</html>

在子窗口中监听 onmessage 事件,并用 JavaScript 实现显示父窗口发送过来的数据。
清单 5. 子窗口中监听 onmessage 事件,显示父窗口发送来的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<html> 
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Web page from child.com</title>
<script type="text/JavaScript">
//event 参数中有 data 属性,就是父窗口发送过来的数据
window.addEventListener("message", function( event ) {
// 把父窗口发送过来的数据显示在子窗口中
document.getElementById("content").innerHTML+=event.data+"<br/>";
}, false );

</script>

</head>
<body>
Web page from http://child.com:8080
<div id="content"></div>
</body>
</html>

图 2. 父窗口嵌入子窗口
父窗口嵌入子窗口
图 3. 父窗口发送数据到子窗口
父窗口发送数据到子窗口
WebSockets
WebSockets 简介
在 Web 应用中,HTTP 协议决定了客户端和服务端连接是短连接,即客户端 Request,服务端 Response,连接断开。要想实现客户端和服务端实时通信,只能通过客户端轮询来实现。服务端推送数据也并不是字面上意思上的直接推,其实还是客户端自己取。WebSockets 是 HTML5 规范新引入的功能,用于解决浏览器与后台服务器双向通讯的问题,使用 WebSockets 技术,后台可以随时向前端推送消息,以保证前后台状态统一。
在 WebSockets 中使用 send 和 onmessage
由于文本主要介绍 postMessage(send) 和 onmessage 客户端 API 的应用,而 WebSockets 涉及到服务器端代码的实现,所以本文将选取最简单的服务器端框架来编写服务器代码。WebSockets 服务器端有 jetty 提供的基于 Java 的实现,有 WebSocket-Node 基于 Node.js 的实现,在 .Net 4.5 中也直接提供了 WebSockets 的支持。本文将使用 WebSocket-Node 提供的示例代码,稍作修改作为 WebSockets 的服务器端。关于 node.js 的介绍以及使用请参考 node.js 官方网站 node.js,关于 WebSocket-Node 的使用请参考 WebSocket-Node。
首先,需要在客户端通过 JavaScript 代码 new 一个 WebSocket 实例出来,参数是实现 WebSocket 服务器端 URL 地址。然后在这个实例上监听 onmessage 事件接收服务器端发送过来的数据。当然,客户端也可以调用 send 方法,发送数据到服务器端。
清单 6. 创建 WebSocket 对象,并监听 onmessage 事件

1
2
3
4
5
6
7
8
9
connect : function() { 
var location ="ws://localhost:8000/";
// 创建 WebSockets 并传入 WebSockets server 地址
this._ws =new WebSocket(location);
this._ws.onmessage=this._onmessage;
//WebSockets 还提供了 onopen 以及 onclose 事件
this._ws.onopen =this._onopen;
this._ws.onclose =this._onclose;
}

在 _onmessage 方法中,接收数据,并显示在页面上
清单 7. _onmessage 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
_onmessage : function(event) { 
//event 参数中有 data 属性,就是服务器发送过来的数据
if (event.data) {
var messageBox = document.getElementById('messageBox');
var spanText = document.createElement('span');
spanText.className ='text';
// 把服务器发送过来的数据显示在窗口中
spanText.innerHTML = event.data;
var lineBreak = document.createElement('br');
messageBox.appendChild(spanText);
messageBox.appendChild(lineBreak);
messageBox.scrollTop = messageBox.scrollHeight
- messageBox.clientHeight;
}
},

在 _onopen 方法中,调用 _send 方法发送一条消息到服务器端,告之连接已经建立。在 _onclose 方法中,把 WebSocket 的实例设置成 null,释放资源。
清单 8. _onopen,_onclose 以及 send 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
_onopen : function() { 
server._send("Client:Open WebSockets,"+new Date());
},
//message 参数就是客户端向服务器端发送的数据
_send : function(message) {
if (this._ws)
this._ws.send(message);
},
// 此方法提供外部代码调用
send : function(text) {
if (text !=null&& text.length >0)
server._send(text);
},

_onclose : function(m) {
this._ws =null;
}

把这些方法封装在一个 server 对象中,方便提供外部调用。用户只需要先调用 server 的 connect 方法建立连接,然后调用 send 方法发送数据。
清单 9. 封装客户端实现

1
2
3
4
5
6
7
8
9
var server = { 
// 对外主要提供 connect 和 send 方法
connect : function() {...},
_onopen : function() {...},
_send : function(message) {...},
send : function(text) {...},
_onmessage : function(event) {...},
_onclose : function(m) {...}
};

在服务器端,通过 JavaScript 语言简单修改 WebSocket-Node 中提供的 echo-server.js 示例即可。这里只展示关键代码部分,其它代码请参见 WebSocket-Node 示例。
清单 10. WebSockets 服务器端简单实现
// 监听客户端的连接请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
wsServer.on('connect', function(connection) { 
function sendCallback(err) {
if (err) console.error("send() error: " + err);
}
// 监听客户端发送数据的请求
connection.on('message', function(message) {
if (message.type === 'utf8') {// 区别客户端发过来的数据是文本还是二进制类型
connection.sendUTF(
"Server:Get message:<br/>"+message.utf8Data, sendCallback
);
}
else if (message.type === 'binary') {
connection.sendBytes(message.binaryData, sendCallback);
}
});
connection.on('close', function(reasonCode, description) {
});
});

图 4. 点击 Connect 按钮
点击 Connect 按钮
图 5. 输入内容,单击 Send Message 按钮
输入内容,单击 Send Message 按钮
Server-Sent Events
Server-Sent Events 简介
HTML5 Server-Sent 事件模型允许您从服务器 push 实时数据到浏览器。本文我们将介绍利用 Eventsource 对象处理与页面间的接收和发送数据。在客户端,我们使用 HTML5+JavaScript,服务端使用 Java。在现存的 Ajax 模式中,web 页面会持续不断地请求服务器传输新数据,由客户端负责请求数据。而在服务端发送模式下,无需在客户端代码中执行连续的数据请求,而是由服务端 push 推送更新。一旦您在页面中初始化了 Server-Sent 事件,服务端脚本将持续地发送更新。客户端 JavaScript 代码一旦接收到更新就将新的数据写入页面中展示出来。
在 Server-Sent Events 中使用 onmessage
Server-Sent Events 和 WebSockets 有相同之处,WebSockets 实现了服务器端以及客户端的双向通信功能,而 Server-Sent Events 则仅是指服务器端到客户端的单向通信,而且 Server-Sent Events 同样需要服务器端的实现,本文将使用基于 Java 的 Servlet 技术实现服务器端。关于服务器端向客户端写数据的格式,可以参考 W3C 关于 Server-Sent Events 的规范文档 Server-Sent Events。由于是服务器端到客户端的单向通信,所以在 Server-Sent Events 中没有 postMessage 方法。
首先,在客户端通过 JavaScript 代码 new 一个 EventSource 实例出来,参数是实现 EventSource 服务器端 URL 地址。然后在这个实例上监听 onmessage 事件接收服务器端发送过来的数据。
清单 11. 创建 EventSource 对象,并监听 onmessage 事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
if (!!window.EventSource) { 
// 创建 EventSource 实例,传入 server 地址
var source = new EventSource('/TestHTML5/ServerSentEvent');
} else {
console.log("Your browser doesn't support server-sent event");
}
// 监听 message 事件,等待接收服务器端发送过来的数据
source.addEventListener('message', function(event) {
//event 参数中有 data 属性,就是服务器发送过来的数据
console.log(event.data);
}, false);

//EventSource 还提供了 onopen 以及 onerror 事件
source.addEventListener('open', function(event) {
}, false);

source.addEventListener('error', function(event) {
if (event.readyState == EventSource.CLOSED) {
}
}, false);

服务器端,在 Java 语言实现的 Servlet doGet 方法中使用 response 对象向客户端写数据
清单 10. 服务器端简单实现

1
2
3
4
5
6
7
8
9
10
11
12
// 这里必须设置 Content-Type 为 text/event-stream 
response.setHeader("Content-Type", "text/event-stream");
response.setHeader("Cache-Control", "no-cache");
response.setCharacterEncoding ("UTF-8");

String id = new Date().toString();
response.getWriter().println("id:"+id);
// 向客户端写两行数据
response.getWriter().println("data:server-sent event is working.");
response.getWriter().println("data:test server-sent event multi-line data");
response.getWriter().println();
response.getWriter().flush();

图 6. Server-Sent Events 运行结果
Server-Sent Events 运行结果
结束语
本文详细介绍了 postMessage(send)和 onmessage API 在客户端的应用情况,可以看到在不同的场景中这两个方法的应用模式都是类似的。postMessage 的作用就是传递数据,而 onmessage 的作用就是接收数据。掌握此组 API 对以后开发 HTML 5 应用程序将会有所帮助。本文 Web Workers,Cross-document messaging,WebSockets 的代码在 Firefox 14 下通过测试,Server-Sent Events 的代码在 Chrome 16 下通过测试。

Top

PHP 浮点数计算比较及取整不准确的解决方法

PHP 浮点数计算比较及取整不准确的解决方法
浮点数计算结果比较
一则浮点数计算例子如下:

1
2
3
$a = 0.2+0.7;
$b = 0.9;
var_dump($a == $b);

打印出的结果是:bool(false)。也就是说在这里 0.2+0.7 的计算结果与 0.9 并不相等,这显然是有违我们的常识的。
对此问题,PHP官方手册曾又说明:显然简单的十进制分数如 0.2 不能在不丢失一点点精度的情况下转换为内部二进制的格式。这和一个事实有关,那就是不可能精确的用有限位数表达某些十进制分数。例如,十进制的 1/3 变成了 0.3333333…。
我们将上面的变量用双精度格式打印出来:

1
2
3
4
5
$a = 0.2+0.7;
$b = 0.9;
printf("%0.20f", $a);
echo '<br />';
printf("%0.20f", $b);

输出结果如下:
0.89999999999999991118
0.90000000000000002220
显然在这里,实际上作为浮点型数据,其精度已经损失了一部分,达不到完全精确。所以永远不要相信浮点数结果精确到了最后一位,也永远不要比较两个浮点数是否相等。需要说明的是,这不是PHP的问题,而是计算机内部处理浮点数的问题!在 C、Java 等语言中也会遇到同样的问题。
所以要比较两个浮点数,需要将其控制在我们需要的精度范围内再行比较,因此使用 bcadd() 函数来对浮点数想加并进行精度转换(为字符串):

1
var_dump(bcadd(0.2,0.7,1) == 0.9);   // 输出:bool(true)

浮点数取整
在《PHP 取整函数 ceil 与 floor》一文中,曾有例子:

1
2
3
<?php
echo ceil(2.1/0.7); // 输出:4
?>

经过上面对浮点数计算的探讨,知道这是浮点数计算结果不完全精确造成的:

1
2
3
<?php
printf("%0.20f", (2.1/0.7)); // 输出:3.00000000000000044409
?>

经过上面对浮点数计算的探讨,知道这是浮点数计算结果不完全精确造成的,因此使用 round() 函数处理一下即可:

1
2
3
<?php
echo ceil( round((2.1/0.7),1) );
?>

虽然 round() 函数是按照指定的精度进行四舍五入,但保留小数点后一位,对我们的取整结果是没影响的。

Top

项目的前后期

一个项目在前期支持用面相对象,减少用面相过程。

特别是在项目需要在后期维护,进行方法重置的时候。

如果一个项目不需要重构,初次就能定版,那就任性的面相过程吧,

到项目经理,改需求的时候,夜里明亮的都是程序猿.

Top

node.js运行HelloWorld

Win下 node.js入门,创建Helloword

1.从官网下载安装包

http://www.nodejs.org/download/

2.安装Node.js

3.在node.js根目录下,创建项目文件 /helloworld

4.在helloworld下,编写文件helloworld.js

1
console.log('helloworld.js');

5.运行命令行

-》//输入node,就进入node.js的终端(node.js直接配置好了环境变量,大爱)

6.切换至项目目录(这步至关重要)

7.运行命令

1
node helloworld.js

Top

ajax长轮播,后台推送请求

ajax长轮播,后台推送请求
用于后台推送数据,处理后可以进行浏览器的控制

用session区分客户端,根据对session的操作来处理客户端

本考虑用Node.js或者html5的推送,因时间有限

js处理部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function al(){
setTimeout("alert()",3000);
}
function alert(argument) {
$.ajax({
type: 'GET',
async: false,
url: "http://push.com/index.php",
data: {

url: ""
},
success: function(a) {
if(a){
console.log(a);
al();
}else{
console.log('error');
al();
}
},
error: function() {}
})

}
al();

PHP部分

开启session

session的信息存储到数据库中

对数据库操作

Top