NodeJS實(shí)戰(zhàn)--使用NodeJS實(shí)現(xiàn)前后端的聯(lián)調(diào)

原文鏈接:http://www.reibang.com/p/2a9367afe9e7

1510997059(1).jpg

1. 將原項(xiàng)目遷移進(jìn)入KOA2篮绰,并順利通過(guò)index/index路由進(jìn)行訪問(wèn)

1.1 新建項(xiàng)目,配置項(xiàng)目結(jié)構(gòu)所需的一系列的文件缓升,使 index/index 可以打開

將原項(xiàng)目 Praisethumb 拖拽到 sublime 編輯器中,新建一個(gè)koatest 文件夾

打開小黑窗進(jìn)入koatest 文件夾中

cd Desktop

cd koatest

初始化項(xiàng)目

npm init

找尋 koa2 包教程蕴轨,www.npmjs.com-> 搜索框輸入koa2

參考鏈接:https://www.npmjs.com/package/koa2

開始配置koa2 -> 在小黑窗中安裝koa2包

npm install koa@next

在koatest文件夾中新建文件 app.js港谊, copy 如下代碼

const Koa = require('koa');

const app = new Koa();

// response

app.use(ctx => {

ctx.body = 'Hello Koa';

});

app.listen(3000);

由于使用的是 ES6 所以將 require 引用 改為 import name from 'name'

import Koa from 'koa';

const app = new Koa();

// response

app.use(ctx => {

ctx.body = 'Hello Koa';

});

app.listen(3000);

此時(shí)在小黑窗中輸入 node app.js 會(huì)報(bào)如下的錯(cuò)誤,原因是為將ES6 代碼編譯為 可解析的 ES5

4Y4V)NM0S7MLXBOBDM9NH2G.png

開始安裝編譯依賴包 babel 橙弱,在此闡述一下 -dev 的問(wèn)題歧寺,安裝包時(shí)加 -dev 說(shuō)明其只在開發(fā)環(huán)境下使用而上線時(shí)有命令可以直接將其去掉, babel 便是此類的安裝包

npm install babel-preset-es2015 --save-dev

http://www.ruanyifeng.com/blog/2016/01/babel.html?20170213113809阮一峰先生的 babel 教程

在項(xiàng)目中新建 .babelrc 棘脐,babel 的配置文件 輸入如下代碼

{

"presets":[

"es2015",

"stage-0"

],

"plugins":[]

}

安裝babel 編譯所需的其他包斜筐,stage-0 是 ES7 的一個(gè)階段,是為了使 babel 可以識(shí)別后面寫的 async 和 await

cnpm install babel-preset-stage-0 --save-dev

http://www.reibang.com/p/c84d52828e45async 和 await 詳解

編譯 app.js 文件蛀缝,并啟動(dòng)服務(wù)

babel app.js -o app_o.js

node app_o.js

啟動(dòng)時(shí)報(bào)了如下錯(cuò)誤顷链,猜測(cè)是由于哪個(gè)包裝的時(shí)候未裝完整便退出了,所以將文件夾中的 node_modules 文件刪除? 再重新安裝一遍項(xiàng)目所需的包 cnpm install? 再次啟動(dòng) node app_o.js 時(shí)便成功了

1511065654(1).jpg

啟動(dòng)成功后屈梁,在瀏覽器中輸入http://localhost:3000/顯示為 Hello Koa證明一切都沒問(wèn)題了

14.此時(shí)需要配置路由 為 /index/index 蕴潦,使用 koa-simple-router 包

https://www.npmjs.com/package/koa-simple-router包的網(wǎng)址

npm install koa-simple-router --save

在 app.js 文件的代碼改為如下所示的

import Koa from 'koa';

import router from 'koa-simple-router';

const app = new Koa();

app.use(router(_ => {

_.get('/', (ctx, next) => {

ctx.body = 'hello'

})

_.post('/name/:id', (ctx, next) => {

// ...

})

})

app.listen(3000);

為了使項(xiàng)目變得更加的分化明了

新建一個(gè) midddleware 文件夾放項(xiàng)目的容錯(cuò)文件

新建一個(gè) config 文件夾放項(xiàng)目的配置文件

新建一個(gè) controller 文件夾放項(xiàng)目的路由配置文件

新建一個(gè)向后端請(qǐng)求數(shù)據(jù)的文件夾 models

新建一個(gè)放 html 頁(yè)面的文件夾 views

再加一個(gè)放靜態(tài)文件 .css .js 的文件夾 public

文件創(chuàng)建解構(gòu)如下

public -> css -> index.css

public -> scripts -> index.js

controller -> initController.js

controller -> indexController.js

編輯 initController.js 文件,將 app.js 文件中的路由配置方法代碼拿到 該文件中略加修改俘闯,最后講方法導(dǎo)出

import index from './indexController';//引入 indexController 文件導(dǎo)出的方法

const controllerInit = {

//配置初始化函數(shù)

init(app, router) {

app.use(router(_ => {

_.get('/index/index', index.index())

}))

}

}

//導(dǎo)出初始化方法潭苞,使其全局可用

export default controllerInit;

編輯 indexController.js 文件,并導(dǎo)出該方法給 initController.js 文件使用

const indexController ={

index(){

return async(ctx,next)=>{

ctx.body = await ctx.render('index.html',function(){

title:'大拇指點(diǎn)贊'

})

}

}

}

// 導(dǎo)出該方法給 initController.js 文件使用

export default indexController;

在 app.js 文件中引用 initController 并執(zhí)行

import initController from './controller/initController';

initController.init(app,router);

由于在controller js 文件中都使用了 koa-swig 框架中的 rander 函數(shù)真朗,而且需要這個(gè)框架在靜態(tài)文件中引用文件此疹,所以要引用 koa-swig

https://www.npmjs.com/package/koa-swig包的網(wǎng)址

npm install koa-swig --save

https://www.cnblogs.com/elementstorm/p/3142644.htmlswig 使用指南

在 swig 使用指南中找到 模板繼承模塊,在項(xiàng)目中的 views 文件夾中新建 layout.html 和 index.html 將如下代碼 copy 進(jìn)去

layout.html

{% block title %}My Site{% endblock %}

{% block head %}

{% endblock %}

{% block content %}{% endblock %}

index.html

{% extends 'layout.html' %}

{% block title %}My Page{% endblock %}

{% block head %}

{% parent %}

{% endblock %}

{% block content %}

This is just an awesome page.

{% endblock %}

以為用的是 koa2 所以用 swig 時(shí)還要引用 co 模塊遮婶,該模塊無(wú)需安裝蝗碎,在 app.js 文件中輸入如下代碼

import co from 'co';

app.context.render = co.wrap(render({

root: __dirname + 'views',

autoescape: true,

cache: 'memory', // disable, set to false

ext: 'html',

writeBody: false

}));

html 文件中相互引用路徑時(shí)需要安裝 koa-static 來(lái)配置

npm install koa-static --save

在 app.js 文件中輸入如下代碼

import serve from 'koa-static';

app.use(serve(__dirname + '/test/fixtures'));

在 config 文件夾中新建? config.js 文件

http://es6.ruanyifeng.com/?search=map&x=0&y=0#docs/set-mapES

6-Map 方法詳述

安裝 path

npm? install path --save-dev

編輯 config.js 文件,將方法導(dǎo)出 app.js 會(huì)使用

import path from 'path';

const CONFIG = new Map();

CONFIG.set('port',3000);

CONFIG.set('staticDir',path.join(__dirname,'..','public'));

CONFIG.set('viewDir',path.join(__dirname,'..','views'));

export default CONFIG;

在 app.js 文件中引入 CONFIG 并修改配置路徑

import CONFIG from './config/config';

initController.init(app,router);

app.context.render = co.wrap(render({

root: CONFIG.get('viewDir'),

autoescape: true,

cache: 'memory', // disable, set to false

ext: 'html',

writeBody: false

}));

app.use(serve(CONFIG.get('staticDir')));

app.listen(CONFIG.get('port'));

編譯文件

babel app.js -o app_o.js? //期間莫名其妙報(bào)了錯(cuò)旗扑,然后檢查了下需要引用的包蹦骑,看看 package.json 文件中是否存在沒有的安裝一遍,之后還是報(bào)錯(cuò)臀防,便將 node_modules 文件夾刪掉 在將所有的包重裝了一遍 npm install 可以了

進(jìn)入 config 和 controller 文件夾中眠菇,將里面的 .js 文件后綴名改為 .es边败,再在命令行中進(jìn)行編譯

cd config

babel config.es -o config.js

cd ..

cd controller

babel initController.es -o initController.js

babel indexController.es -o indexController.js

啟動(dòng)服務(wù)

cd..

node app_o.js

此時(shí)報(bào)了如下的錯(cuò)誤,

1511073380(1).jpg

原因是在 indexController 中用到了 async 和 await 但是并沒有編譯的很好捎废,因?yàn)?babel 默認(rèn)是不會(huì)編譯較高級(jí)的函數(shù)的笑窜,所以需要裝兩個(gè)包使其支持

cnpm install babel-register --save-dev

cnpm install babel-polyfill --save-dev

裝好之后在 app.js 文件中引入

import babel_co from 'babel-core/register';

import babel_po from 'babel-pocyfill';

再編譯一遍文件

babel app.js -o app_o.js

cd controller

babel indexcontroller

babel indexController.es -o indexController.js

運(yùn)行服務(wù) 報(bào)錯(cuò)為如下圖

image.png

在 app.js 文件中引入 CONFIG

import CONFIG from './config/config';

編譯修改過(guò)的文件

babel app.js -o app_o.js

cd config

babel config.es -o config.js

切記每次修改了 .es 都需要在重新編譯一遍

運(yùn)行服務(wù)

node app_o.js

在瀏覽器打開頁(yè)面http://localhost:3000/index/index展示如下圖所示? 便表示成功了接下來(lái)就是第二步將原項(xiàng)目遷移過(guò)來(lái)

1511076432(1).jpg

1.2 將之前所做的 項(xiàng)目 Praisethumb 中的文件配置到新項(xiàng)目中

1.將之前的 css 樣式 放到 koatest 項(xiàng)目中的 index.css 文件中

{

margin: 0;

padding: 0;

}

body {

background-color: #b1c8ac;

padding: 50px;

position: relative;

height: 600px;

}

.a {

position: absolute;

left: 0;

right: 0;

top: 0;

bottom: 0;

margin: auto;

background-color: #ffcaaa;

width: 226px;

height: 360px;

border-radius: 38px 0 0 38px;

border: 1px solid #95755e;

border-width: 1px 0 1px 1px;

}

.a:before {

content: " ";

display: block;

position: absolute;

width: 246px;

height: 240px;

border-top: 1px solid #95755e;

bottom: 0;

top: 0;

right: 0;

left: 0;

margin: auto auto auto -224px;

background-color: #ffcaaa;

}

.a:after {

content: " ";

display: block;

position: absolute;

width: 150px;

height: 90px;

border: 1px solid #95755e;

border-width: 1px 1px 0 0;

border-radius: 0 45px 45px 0;

bottom: 0;

top: 0;

right: 0;

left: 0;

margin: 0 auto auto 30px;

background-color: #ffcaaa;

transform: rotate(-65deg);

transform-origin: left top;

box-shadow: -4px -4px 22px 2px #ffcaaa inset, -4px 4px 30px 2px #ffcaaa inset, -25px 2px 10px 3px #fce0d4 inset, -80px 2px 10px 1px #ffcaaa inset, -100px 2px 20px 0px #efb38f inset;

transition: all .3s;

}

.b {

width: 180px;

height: 90px;

border: 1px solid #95755e;

position: absolute;

border-radius: 45px;

box-shadow: -4px -4px 22px 2px #ffcaaa inset, -4px 4px 30px 2px #ffcaaa inset, -25px 2px 10px 3px #fce0d4 inset;

background-color: #ffcaaa;

z-index: -1;

left: 0;

right: 0;

top: 0;

bottom: 0;

margin: auto -90px -1px auto;

-webkit-box-reflect: above 178px;

box-reflect: above 178px;

}

.b:before {

content: " ";

display: block;

position: absolute;

width: 180px;

height: 90px;

border: 1px solid #95755e;

right: 0;

top: -91px;

border-radius: 45px;

border-width: 1px 1px 1px 0;

box-shadow: -4px -4px 22px 2px #ffcaaa inset, -4px 4px 30px 2px #ffcaaa inset, -25px 2px 10px 3px #fce0d4 inset;

background-color: #ffcaaa;

}

.c {

width: 180px;

height: 90px;

border: 1px solid #95755e;

position: absolute;

border-radius: 45px;

box-shadow: -4px -4px 22px 2px #ffcaaa inset, -4px 4px 30px 2px #ffcaaa inset, -25px 2px 10px 3px #fce0d4 inset;

background-color: #ffcaaa;

z-index: -1;

left: 0;

right: 0;

top: 0;

bottom: 0;

margin: 90px -90px -1px auto;

/-webkit-box-reflect: above 178px;

box-reflect: above 178px;

/

}

.c:before {

content: " ";

display: block;

position: absolute;

width: 180px;

height: 90px;

border: 1px solid #95755e;

right: 0;

top: -91px;

border-radius: 45px;

border-width: 1px 1px 1px 0;

box-shadow: -4px -4px 22px 2px #ffcaaa inset, -4px 4px 30px 2px #ffcaaa inset, -25px 2px 10px 3px #fce0d4 inset;

background-color: #ffcaaa;

}

/.b:after{content: " ";display: block;position: absolute;width: 180px;height:90px;border: 1px solid #95755e;right: 0;top:182px;border-radius: 45px;border-width: 1px 1px 1px 0;box-shadow:-4px -4px 22px 2px #ffcaaa inset, -4px 4px 30px 2px #ffcaaa inset, -25px 2px 10px 3px #fce0d4 inset;background-color: #ffcaaa;}/

.hide {

opacity: 0;

color: red;

font-size: 60px;

position: absolute;

right: 60px;

top: 150px;

}

.num {

animation: myani .6s ease;

-moz-animation: myani .6s ease;

-webkit-animation: myani .6s ease;

-o-animation: myani .6s ease;

}

@keyframes myani() {

form {

opacity: 0;

top: 150px;

}

to {

opacity: 1;

top: 50px;

}

}

@-moz-keyframes myani {

form {

opacity: 0;

top: 150px;

}

to {

opacity: 1;

top: 50px;

}

}

@-webkit-keyframes myani {

form {

opacity: 0;

top: 150px;

}

to {

opacity: 1;

top: 50px;

}

}

@-o-keyframes myani {

form {

opacity: 0;

top: 150px;

}

to {

opacity: 1;

top: 50px;

}

}

:root {

--green: #b1c8ac;

}

body {

background-color: var(--green);

}

將 html 內(nèi)容也拿過(guò)來(lái)

index.html

{% extends 'layout.html' %}

{% block title %}My Page{% endblock %}

{% block head %}

{% parent %}

{% endblock %}

{% block content %}

+1

SystemJS.config({

//使用的 js 文件的文件夾路徑

baseURL: '/scripts'

});

//使用的 js 文件名稱

SystemJS.import('index-es.js').then(function(m) {

$.extend({

//將自己寫的函數(shù)掛載到 jq 上稱為一個(gè)插件

thumb:m.default.Thumb

})

//回調(diào)函數(shù)

callBack();

});

//定義回調(diào)函數(shù)

function callBack() {

//為頁(yè)面元素添加方法

var f = new $.thumb(0,$('#thumb'));

f.clickAction();

}

{% endblock %}

拿 js

window.add = function (num) {

return num + 1;

}

將編譯過(guò)的 點(diǎn)擊小手子類繼承父類的 js文件(index.es.js)復(fù)制到 項(xiàng)目的 scripts 文件夾下

index-es.js

'use strict';

Object.defineProperty(exports, "__esModule", {

value: true

});

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.proto= superClass; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var PraiseButton = function () {

function PraiseButton(num, element) {

_classCallCheck(this, PraiseButton);

this.num = num;

this.element = element;

_createClass(PraiseButton, [{

key: 'clickAction',

value: function clickAction() {

var _this = this;

this.element.click(function () {

if (_this.num < 10) {

_this.element.css('-webkit-filter', 'grayscale(0)');

$('#animation').addClass('num');

_this.num = add(_this.num);

setTimeout(function () {

$('#animation').removeClass('num');

}, 1000);

} else {

_this.element.css('-webkit-filter', 'grayscale(1)');

_this.num = 0;

}

console.log(_this.num);

});

}

}]);

return PraiseButton;

}();

var Thumb = function (_PraiseButton) {

_inherits(Thumb, _PraiseButton);

function Thumb(num, element) {

_classCallCheck(this, Thumb);

return _possibleConstructorReturn(this, (Thumb.proto|| Object.getPrototypeOf(Thumb)).call(this, num, element));

}

return Thumb;

}(PraiseButton);

exports.default = { Thumb: Thumb

// let? f = new Thumb(0,$('#thumb'));

// f.clickAction();

};

重啟服務(wù)

node app_o.js

刷新http://localhost:3000/index/index頁(yè)面,發(fā)現(xiàn)項(xiàng)目已經(jīng)移植成功

2. 使用 PHP + MySQL 完成點(diǎn)贊借口登疗,實(shí)現(xiàn)用戶點(diǎn)擊一次更新數(shù)據(jù)庫(kù)點(diǎn)贊次數(shù)

在項(xiàng)目中新建一個(gè) praise.php 文件

編輯文件


//用php的面向?qū)ο髞?lái)寫

/**

* 新建一個(gè)類

*/

class Conmysql

{

//定義所需的變量

//public關(guān)鍵字表示屬性或方法是公開可見的

public $servername;

public $username;

public $password;

public $dbname;

}

?>

用 XAMPP 啟動(dòng) Apache 和 MySQL

1511081397(1).jpg

在瀏覽器中打開http://localhost/phpmyadmin/頁(yè)面

在左側(cè)操作欄中點(diǎn)擊【新建】

輸入新數(shù)據(jù)庫(kù)的名字 praise 點(diǎn)擊【創(chuàng)建】

新建數(shù)據(jù)表 text 2

字段分別為? id 和 num

id 需要設(shè)置為主鍵

點(diǎn)擊保存

具體設(shè)計(jì)如下圖所示

image.png

在 text 數(shù)據(jù)表中手動(dòng)添加一條數(shù)據(jù)

點(diǎn)擊數(shù)據(jù)表【text】

點(diǎn)擊 【SQL】

點(diǎn)擊【INSERT】

將輸入域的值修改為如下所示排截,點(diǎn)擊【執(zhí)行】

INSERT INTO `text`(`id`, `num`) VALUES (1,0)

在 php 文件中編輯


//用php的面向?qū)ο髞?lái)寫

/**

* 新建一個(gè)類

*/

class Conmysql

{

//定義所需的變量

//public關(guān)鍵字表示屬性或方法是公開可見的

public $servername;

public $username;

public $password;

public $dbname;

public $con = null;

//添加構(gòu)造方法

public function __construct($servername,$username,$password,$dbname){

$this->servername = $servername;

$this->username = $username;

$this->password = $password;

$this->dbname = $dbname;

}

//創(chuàng)建數(shù)據(jù)庫(kù)鏈接方法

//參考網(wǎng)址:http://www.runoob.com/php/php-mysql-connect.html -> 實(shí)例 (PDO)

public function getConnection(){

//這里用的是 PDO 方法

try {

$dsn = "mysql:host=$this->servername;dbname=$this->dbname";

$this->con = new PDO($dsn, $this->username, $this->password);

//echo "連接成功";

}

catch(PDOException $e)

{

echo $e->getMessage();

}

}

//更新數(shù)據(jù)的方法

public function updateDate($sql){

//如果未連接的話就鏈接到數(shù)據(jù)庫(kù)

if($this->con == null){

$this->getConnection();

}

//執(zhí)行sql

//參考鏈接:http://www.runoob.com/php/php-mysql-insert.html -> 實(shí)例 (PDO)

$res=$this->con->exec($sql);

//關(guān)閉鏈接

$this->closeCon();

}

//關(guān)閉鏈接的方法

public function closeCon(){

$this->con = null;

}

}

/**

* 創(chuàng)建子類

*/

class realConn extends Conmysql

{

//繼承父類的構(gòu)造方法

public function __construct($servername,$username,$password,$dbname){

parent::__construct($servername,$username,$password,$dbname);

}

//真正執(zhí)行 sql 的方法

public function updateRealDate(){

$sql = "UPDATE text SET num=num+1 WHERE id=1";

$this->updateDate($sql);

}

}

//將子類實(shí)例化執(zhí)行方法

$praiseCon = new realConn('localhost','root','','praise');

$praiseCon->updateRealDate();

?>

將 praise.php 文件復(fù)制到 C:\xampp\htdocs 文件夾下,在瀏覽器中打開http://localhost/praise.php辐益,再查看 text 數(shù)據(jù)表中會(huì)發(fā)現(xiàn) num 的值為 1 断傲,刷 php 頁(yè)面一次值便會(huì)加 1,至此點(diǎn)贊接口便完成了

3. 使用KOA2+ES6封裝PHP點(diǎn)贊接口智政,并建立路由

1.在 koatest 項(xiàng)目文件夾的 models 文件夾中新建一個(gè) indexmodel.js 文件

編輯 indexmodel.js 文件

import rpA from 'request-promise';

class indexModel {

constructor(ctx) {

this.ctx = ctx;

}

//為了實(shí)現(xiàn)數(shù)據(jù)庫(kù)更新建立方法 傳數(shù)據(jù)的接口

updateNum() {

//在這里 return 一個(gè) promise 模塊傳入 initController.js 再在indexController.js 中調(diào)用需要用到一個(gè)模塊 request-promise? 參考網(wǎng)址:https://www.npmjs.com/package/request-promise

// 獲取文件

const options = {

uri: 'http://localhost/praise.php',

method:'GET'

};

return new Promise((resolve,reject)=>{

rpA(options).then(function(result){

const info = JSON.parse(result);

if(info){

resolve({data:info.result});

}else{

reject({});

}

})

})

}

}

//將該方法導(dǎo)出认罩,? indexController.js 文件要用到

export default indexModel;

由于 updateNum 方法中需要用到 request-promise 模塊 所以需要安裝兩個(gè)包

參考鏈接:https://www.npmjs.com/package/request-promise

npm install --save request

npm install --save request-promise

編輯 indexController.js 文件

indexController 對(duì)象中增加一個(gè) 提交數(shù)據(jù)的方法

//引入所需方法的文件

import indexModel from '../models/indexModel';

update(){

return async(ctx,next)=>{

const indexM = new indexModel(ctx);

ctx.body = await indexM.updateNum();

}

}

編輯 initController.js 文件

將 indexController 提交數(shù)據(jù)的方法注冊(cè)到 一個(gè)新的路由上

_.get('/index/update', index.update());

babel 編譯文件

將 indexmodel.js 重命名為 indexmodel.es

cd models

babel indexmodel.es -o indexmodel.js

cd ..

cd controller

babel? indexController.es -o indexController.js

babel initController.es -o initController.js

此時(shí)運(yùn)行服務(wù)會(huì)發(fā)現(xiàn)小手點(diǎn)擊并沒有與服務(wù)器關(guān)聯(lián)起來(lái),此時(shí)需要用 axios 模塊來(lái)使其連接到 koa2 點(diǎn)贊接口上

4. 將用戶點(diǎn)擊事件通過(guò) axios 鏈接到 KOA2 點(diǎn)贊接口

在 koatest 項(xiàng)目中的 scripts 文件夾中新建 index.es 文件女仰,并將 praisethumb 項(xiàng)目中的 scripts -> index.js 文件代碼復(fù)制過(guò)來(lái)

class PraiseButton{

constructor(num,element){

this.num = num;

this.element = element;

}

clickAction(){

this.element.click(()=>{

if(this.num < 10){

this.element.css('-webkit-filter','grayscale(0)');

$('#animation').addClass('num');

this.num = add(this.num);

setTimeout(function () {

$('#animation').removeClass('num');

},1000);

}else{

this.element.css('-webkit-filter','grayscale(1)');

this.num = 0;

}

console.log(this.num);

})

}

}

class Thumb extends PraiseButton{

constructor(num,element){

super(num,element)

}

}

export default{Thumb}

// let? f = new Thumb(0,$('#thumb'));

// f.clickAction();

編輯 index.es 文件猜年,這里是要用 axios 模塊來(lái)使其連接到 koa2 點(diǎn)贊接口上

參考鏈接:https://www.npmjs.com/package/axios

這里有三種引用的方法:npm 裝包抡锈,瀏覽器裝包疾忍,cdn,這里我們用的是 cdn 方法床三,將如下代碼 copy 至 index.html 文件中

將如下代碼 copy 至 index.es -> this.element.click 點(diǎn)擊事件中

axios.get('/index/update')

.then(function (response) {

console.log(response);

})

.catch(function (error) {

console.log(error);

});

編修改過(guò)的文件 index.es

cd public\scripts\

babel index.es -o index-es.js

運(yùn)行服務(wù)

cd ../..

node app_o.js

點(diǎn)擊時(shí)頁(yè)面http://localhost:3000/index/index報(bào)如下圖所示的錯(cuò)誤

image.png

編輯 praise.php 文件中的 updateDate 方法

//更新數(shù)據(jù)的方法

public function updateDate($sql){

//如果未連接的話就鏈接到數(shù)據(jù)庫(kù)

if($this->con == null){

$this->getConnection();

}

//向前臺(tái)輸出 json 格式的數(shù)據(jù)

header('content-type:application/json;charset=utf8');

//執(zhí)行sql

//參考鏈接:http://www.runoob.com/php/php-mysql-insert.html -> 實(shí)例 (PDO)

$res=$this->con->exec($sql);

//執(zhí)行之后 輸出返回的數(shù)據(jù)

$arr = array('result'=>$res);

echo json_encode($arr);

//關(guān)閉鏈接

$this->closeCon();

}

運(yùn)行服務(wù)一罩,發(fā)現(xiàn)又報(bào)了 404 ,排查之后發(fā)現(xiàn)是 index.es 文件中的 uodate 寫成了 uodete 撇簿,誒聂渊,修改后 編譯 ,再運(yùn)行點(diǎn)擊一下小手四瘫,數(shù)據(jù)庫(kù)里面的 num 的值 +1 證明成功了

需要注意的是 php返回的數(shù)據(jù)必須嚴(yán)格是 json 格式的 不然前臺(tái) .js 文件 (未編譯:indexmodel.es 已編譯 indexmodel.js)中用到的 JSON.parse(result); 會(huì)一直報(bào)錯(cuò)導(dǎo)致頁(yè)面崩潰

cd public\scripts\

babel index.es -o index-es.js

cd../..

node app_o.js

5. 對(duì)用戶連續(xù)點(diǎn)擊事件進(jìn)行稀釋

稀釋所用的方法就是 setTimeout

編輯 index.es 文件

let f = '';

class PraiseButton{

constructor(num,element){

this.num = num;

this.element = element;

}

clickAction(){

this.element.click(()=>{

//判斷事件是否已經(jīng)存在汉嗽,如果存在便會(huì)將其清除掉,所以點(diǎn)擊只會(huì)執(zhí)行最后一次點(diǎn)擊的那次事件

if(f){

clearTimeout(f);

}

f = setTimeout(()=>{

if(this.num < 10){

this.element.css('-webkit-filter','grayscale(0)');

$('#animation').addClass('num');

this.num = add(this.num);

setTimeout(function () {

$('#animation').removeClass('num');

},1000);

axios.get('/index/update')

.then(function (response) {

console.log(response);

})

.catch(function (error) {

console.log(error);

});

}else{

this.element.css('-webkit-filter','grayscale(1)');

this.num = 0;

}

console.log(this.num);

},800)

})

}

}

class Thumb extends PraiseButton{

constructor(num,element){

super(num,element)

}

}

export default{Thumb}

// let? f = new Thumb(0,$('#thumb'));

// f.clickAction();

編譯文件

cd public\scripts\

babel index.es -o index-es.js

運(yùn)行服務(wù)找蜜,稀釋成功

node app_o.js

6. 完成點(diǎn)贊接口的自動(dòng)化測(cè)試饼暑、點(diǎn)贊+1功能的自動(dòng)化測(cè)試、真實(shí)頁(yè)面點(diǎn)擊自動(dòng)化測(cè)試

1. 點(diǎn)贊+1功能的自動(dòng)化測(cè)試

安裝 karma

cnpm install karma --save-dev

安裝斷言庫(kù)洗做、核心弓叛、chrome 啟動(dòng)器

cnpm install karma-jasmine jasmine-core karma-chrome-launcher --save-dev

安裝無(wú)界面瀏覽器、無(wú)界面瀏覽器啟動(dòng)器

cnpm install phantomjs --save-dev

cnpm install karma-phantomjs-launcher --save-dev

karma 初始化生成配置文件 karma.conf.js

karma init

jasmine

no

PhantomJS

yes

5.在項(xiàng)目中新建一個(gè) test 文件夾诚纸,在該文件夾下做三大測(cè)試

將 praisethumb 項(xiàng)目文件夾的中 index.spce.js 文件復(fù)制到 test 文件夾下

編輯 karma.conf.js 文件

files: [

'test/index.spec.js',

'public/scripts/index.js'

],

singleRun: true,

啟動(dòng)測(cè)試撰筷,運(yùn)行成功

karma start

2. 點(diǎn)贊接口的自動(dòng)化測(cè)試

1.先安裝 mocha

cnpm install mocha --save-dev

安裝 supertest

cnpm install supertest --save-dev

在 test 文件夾下新建一個(gè) server.js 文件

編輯 sever.js 文件,這里我們需要用到 supertest 模塊

參考鏈接:https://www.npmjs.com/package/supertest

import requestsuper from 'supertest';

//這里引用的是 app_o.js 文件拿到 app畦徘,所以需要在 app.js 文件中將其導(dǎo)出毕籽,然后再將 app.js 文件編譯為 app_o.js 文件

import app from '../app_o.js';

//先定義一個(gè)拿到端口的方法

function request(){

return requestsuper(app.listen());

}

describe('測(cè)試路由', function() {

it('點(diǎn)贊', function(done) {

request()

.get('/index/update')

.expect(200)

.end(function(err,res){

if(res.data==1)return done(err);

done();

})

});

});

修改 app.js 文件

export default app;

編譯文件

babel app.js -o app_o.js

cd test\

babel server.js -o server-es.js

執(zhí)行 server-es.js 文件

cd ..

mocha test\server-es.js

此時(shí)報(bào)如下圖所示的錯(cuò)誤

image.png

將 mocha 安裝至全局

cnpm install mocha -g

執(zhí)行測(cè)試

mocha test\server-es.js

執(zhí)行成功

image.png

3. 真實(shí)頁(yè)面點(diǎn)擊自動(dòng)化測(cè)試

1.安裝 selenium-webdriver

參考鏈接:https://www.npmjs.com/package/selenium-webdriver

cnpm install selenium-webdriver

2.下面火狐瀏覽器所需的相應(yīng)組件

參考鏈接:https://github.com/mozilla/geckodriver/releases/找到與當(dāng)前設(shè)備匹配的一款點(diǎn)擊下載 我的是 win64

將下載好的壓縮包解壓至 koatest 項(xiàng)目文件夾中抬闯,刪除壓縮包

再安裝兩個(gè)包

cnpm install selenium-standalone --save

cnpm install protractor --save

test 文件夾下新建 e2e.js 文件

編輯 e2e.js 文件

參考鏈接:https://www.npmjs.com/package/selenium-webdriver->? Usage

const {Builder, By, Key, until} = require('selenium-webdriver');

let driver = new Builder()

.forBrowser('firefox')

.build();

//設(shè)置地址

driver.get('http://localhost:3000/index/index');

driver.findElement(By.id('thumb')).click();

const _animation = driver.findElement(By.id('animation'))

driver.wait(_animation.isDisplayed(), 1000);

// driver.quit(); //為了看到效果將關(guān)閉瀏覽器的行為暫時(shí)注釋掉

執(zhí)行測(cè)試腳本 e2e.js 文件

node test\e2e.js

此時(shí)會(huì)發(fā)現(xiàn)瀏覽器打開頁(yè)面后,頁(yè)面并不能加載出來(lái)原因是這個(gè) koatest 項(xiàng)目此時(shí)并沒有處于運(yùn)行狀態(tài)影钉,所以需要新建一個(gè)命令行窗口中執(zhí)行項(xiàng)目運(yùn)行操作

image.png

在新窗口中輸入命令

cd Desktop

cd koatest

node app_o.js

此時(shí)再在之前的命令行窗口中執(zhí)行測(cè)試腳本 e2e.js 文件

node test\e2e.js

整個(gè)實(shí)戰(zhàn)到此結(jié)束画髓。

作者:sunxiaochuan

鏈接:http://www.reibang.com/p/2a9367afe9e7

來(lái)源:簡(jiǎn)書

著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán)平委,非商業(yè)轉(zhuǎn)載請(qǐng)注明出處奈虾。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市廉赔,隨后出現(xiàn)的幾起案子肉微,更是在濱河造成了極大的恐慌,老刑警劉巖蜡塌,帶你破解...
    沈念sama閱讀 219,427評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件碉纳,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡馏艾,警方通過(guò)查閱死者的電腦和手機(jī)劳曹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)琅摩,“玉大人铁孵,你說(shuō)我怎么就攤上這事》孔剩” “怎么了蜕劝?”我有些...
    開封第一講書人閱讀 165,747評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)轰异。 經(jīng)常有香客問(wèn)我岖沛,道長(zhǎng),這世上最難降的妖魔是什么搭独? 我笑而不...
    開封第一講書人閱讀 58,939評(píng)論 1 295
  • 正文 為了忘掉前任婴削,我火速辦了婚禮,結(jié)果婚禮上牙肝,老公的妹妹穿的比我還像新娘唉俗。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著拒担,像睡著了一般妖泄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,737評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼寺酪。 笑死坎背,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的寄雀。 我是一名探鬼主播得滤,決...
    沈念sama閱讀 40,448評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼盒犹!你這毒婦竟也來(lái)了懂更?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,352評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤急膀,失蹤者是張志新(化名)和其女友劉穎沮协,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體卓嫂,經(jīng)...
    沈念sama閱讀 45,834評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡慷暂,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了晨雳。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片行瑞。...
    茶點(diǎn)故事閱讀 40,133評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖餐禁,靈堂內(nèi)的尸體忽然破棺而出血久,到底是詐尸還是另有隱情,我是刑警寧澤坠宴,帶...
    沈念sama閱讀 35,815評(píng)論 5 346
  • 正文 年R本政府宣布洋魂,位于F島的核電站绷旗,受9級(jí)特大地震影響喜鼓,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜衔肢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評(píng)論 3 331
  • 文/蒙蒙 一庄岖、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧角骤,春花似錦隅忿、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至蝉揍,卻和暖如春链峭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背又沾。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工弊仪, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留熙卡,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,398評(píng)論 3 373
  • 正文 我出身青樓励饵,卻偏偏與公主長(zhǎng)得像驳癌,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子役听,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容