说明
这篇博客是给团队内人员的一个模式开发的说明文档,当然对于其他读者也可以了解,不喜勿喷
前言
其实,这种开发模式还是挺少见的,vue自有vue-cli可以使用webpack打包前端项目,然后后端就做后端的活提供数据服务,这样前后端分离的彻底,但是限于笔者个人水平,vue-cli和webpack正在学习中,所以替代的方案,就是这种看起来怪怪的组合,不过实验证明是可行的方案,缺点就是前后分离不是很彻底,毕竟前端的访问路由由thinkPHP框架做了,这样从某种意义上说,前后还是没有完全的分开,但是基本上已经实现了业务和数据的分离
简单介绍一下这种模式
1、三剑客就是HTML+CSS+JS,当然也包含了一些纯HTML的前端框架,比如bootstrap3、easyUI等,这些在项目中使用都是没关系的,不会影响到整体模式的配合
2、Jquery.ajax就是jquery中关于ajax方法的支持,通过ajax来做异步的请求处理,这也是实现前后端分离、业务和数据分离、面向数据编程的关键之处,通过ajax的请求直接对后台的数据接口进行访问,也就是说后台不需要在把变量assign到对应的页面了,而是前端需要数据的时候去访问后台获取数据,我们也可以看到这其实是主动权的一个转换,主动权从后端转向了前端,从要不要都要给变为了需要了再去取
【jQuery.ajax 注意】:这里我要说明一点,vue是数据驱动的框架,jQuery则是偏向于强大而简洁的DOM操作,这两个框架编程的方式大相径庭,我们这里使用了以数据驱动为主的vue,就不需要在使用jQuery的DOM操作了,但是之所以引入Jquery是因为vue自身并不支持Ajax请求,其实vue有一个叫vue-resource的插件可以使用更简洁的API来使用Ajax,但是因为jQuery更容易上手,所以这次使用jQuery.ajax作为发起request的方式
3、VUE单页就是使用VUE做单页的应用,在这种模式下的意思就是在每个页面都引入VUE,路由则交给ThinkPHP框架去做。
我目前对于VUE的认识有两点,一是VUE是一个渐进式框架,所谓渐进式我的理解就是你可以慢慢一点一点的上手,举个例子,比如ThinkPHP这种框架,如果你一开始是写的原生PHP,突然转到使用ThinkPHP框架,你需要先看完整个框架的说明并且使用框架,才能成功搭建你的项目(当然这个例子不是很好,一个是JS框架,一个是PHP框架,我只是想说明渐进式这种概念,笔者也是正在学习VUE的路途中,可能有些错误望指正),但是VUE不是这样的,你只需要学一点用一点就可以,而且VUE的使用并不会影响你其他东西的使用,其他的东西还是按照你的习惯就可以;二是VUE是一个数据驱动的框架,而且有些打破传统的DOM操作的一些特性,比如说,动态数据绑定(比如mustache语法的支持,v指令对数据/事件的绑定等)以及对自定义组件和模板的支持等待,大大提高了前端处理业务的能力,以至于现在很多前端技术比如我们熟知的微信小程序、还有大公司常用的reactJS和AngularJS,包括我们用的VUE都是前端渲染的框架,传统的基于DOM的开发方式比较费时费力而且代码冗余难以维护,所以前端渲染的模式也是一种趋势
4、最后说一下ThinkPHP,ThinkPHP是一个快速、兼容而且简单的轻量级国产PHP开发框架,相对比较友好的一个PHP框架(对比yii来说),因为是国产的,中文文档很详实,版本更新已经到5.x了,我们此次使用的是ThinkPHP3.2.3
总: 我们此次这种模式下,各个框架的作用是什么或者说各个框架承担的角色是什么呢?
三剑客就是负责网页的结构布局和样式,甚至是动画效果(VUE中也有过渡动画可以使用,但是鉴于大家刚入坑不久,我们先不使用)
Jquery.ajax就是负责异步请求
VUE是做业务处理和视图更新
ThinkPHP是做路由和后台数据服务
精简的教程
三剑客不再说了,为了大家方便,我下面以demo实例的方式做一个这种模式下的精简教程
Jquery.ajax
Ajax的产生初衷是为了解决局部刷新的问题,在传统的后端渲染的模式下,用户在前端交互时因为需要后端去做处理并重新加载至页面,所以往往会出现“闪屏”的问题,网速差的话,这种问题就暴露的更明显,所以Ajax技术就通过前端发送一个伪请求(模拟get和post请求)的方式向后端请求数据包,一般来说这个数据包其实就是一个字符串或者对象,这个字符串或者对象的类型有三种,分别是text、json和XML,我们这里就是json字符串和json对象。前端获取到数据包后,通过json的解析方法可以解析出相应的数据结构,再通过js对前端的数据进行刷新,这种方式下,页面不会出现“闪屏”的问题。
原生的ajax用起来不是很方便,Jquery对原生ajax进行封装,给出了$.get、$.post和通用的$.ajax方法,我们用$.ajax就行了,下面是简单的demo
$.ajax({
url : "{:U('Index/searchBook')}",
type : "post",
contentType : "application/x-www-form-urlencoded;charset=utf-8",
data : {
text : that.text
},
dataType : "json",
success : function(data){
if(data.code == 'success'){
//将json字符串转为json对象
var jsonStr = data.data
//去掉字符串中的空格
jsonStr = jsonStr.replace(" ","");
//typeof https://www.cnblogs.com/liu-fei-fei/p/7715870.html
if(typeof jsonStr!='object'){
//去掉饭斜杠
jsonStr = jsonStr.replace(/\ufeff/g,"")
var jsonObj = JSON.parse(jsonStr)
that.booklist = jsonObj
}
}
if(data.code == 'fail'){
layer.msg(data.msg)
}
}
})
$.ajax还有其他的一些不常用的属性,想了解可以看这篇博客 :
https://www.cnblogs.com/jackcheblog/p/7065421.html
当data中text=9787561231944时,这是返回的json对象
{
"code": "success",
"data": "[{\"book_id\":\"1531-5\",\"isbn\":\"9787561231944\",\"title\":\"\\u8f6f\\u4ef6\\u7cfb\\u7edf\\u5f00\\u53d1\\u6307\\u5bfc\\u4e66\",\"author\":\"\\u90d1\\u4f1f\",\"theme\":\"\\u8f6f\\u4ef6\\u5f00\\u53d1\\u7cfb\\u5217\\u4e1b\\u4e66\",\"category\":\"\\u79d1\\u6280\\u7c7b\",\"abstract\":\"\\u8f6f\\u4ef6\\u6d4b\\u8bd5\\u662f\\u8f6f\\u4ef6\\u5de5\\u7a0b\\u5b66\\u79d1\\u7684\\u4e00\\u4e2a\\u91cd\\u8981\\u5206\\u652f\",\"publisher\":\"\\u897f\\u5317\\u5de5\\u4e1a\\u5927\\u5b66\\u51fa\\u7248\\u793e\",\"pub_date\":\"2011-06-10\",\"language\":\"zh_CN\"}]"
}
我们可以通过data.code或者data.data来直接访问到键对应的值,data中的数据是一个json字符串,所以需要先转换为json对象才能使用.
来访问键值对
Vue单页
我们这次的项目使用的是最基本的Vue,有关组件和模板以及构建工具这方面先不涉及
在html中创建一个vue实例
<!DOCTYPE html>
<html>
<head>
<!-- 首先需要引入vue框架文件 -->
<script type="text/javascript" src="__ROOT__/public/syspkg/vue.js"></script>
</head>
<body>
<div id="home">
<div>{{text}}</div>
<div v-on:click="A"></div>
</div>
<script type="text/javascript">
var app = new Vue({
el : '#home',
data : {
text : "创建第一个vue",
},
methods : {
A : function(){
alert(this.text)
}
}
</script>
</body>
</html>
因为vue需要挂载dom节点,所以vue的创建需要在dom结构之后才能真正被实例化,从这个例子中你可以看到所谓数据驱动的意思就是无论是dom元素还是dom的原生事件,vue都是通过data来封装数据,通过methods来驱动数据处理业务,当然一个vue实例中还有其他的驱动方式,如计算属性/侦听器等,这个在有能力的基础上可以自行学习使用
更详细的教程官方文档上比我说的要清楚许多,可以自行查看:vue.js官方教程
我在这里说下对于vue中数组的使用,以及我们要做列表渲染和列表的增删时如何做
vue中data属性中数组(es5语法)其实和json很像,这也是为什么json对象可以直接赋值给vue的数组使用
下面以一个图书管理的表格的增删查为例,改就不说了,和增删差不多的
html
<table class="table table-bordered">
<thead>
<tr>
<th>book_id</th>
<th>ISBN</th>
<th>Title</th>
<th>Author</th>
<th>Theme</th>
<th>Category</th>
<th>Abstract</th>
<th>Publisher</th>
<th>PubDate</th>
<th>Language</th>
<th>options </th>
</tr>
</thead>
<tbody id="add">
<tr v-for="(book,index) in booklist" >
<td>{{book.book_id}}</td>
<td>{{book.isbn}}</td>
<td>{{book.title}}</td>
<td>{{book.author}}</td>
<td>{{book.theme}}</td>
<td>{{book.category}}</td>
<td>{{book.abstract}}</td>
<td>{{book.publisher}}</td>
<td>{{book.pub_date}}</td>
<td>{{book.language}}</td>
<td><a href="javascript:void(0);" v-on:click="removeBook(index)">delete</a> | <a href="javascript:void(0);" v-on:click="updateBook(index)">modify</a></td>
</tr>
</tbody>
</table>
vue.js
var app = new Vue({
el : '#home',
data : {
booklist : [],
}
created : function(){
var that = this
$.ajax({
url : "{:U('Index/getBook')}",
dataType : "json",
success : function(data){
if(data.code == 'success'){
//将json字符串转为json对象
var jsonStr = data.data
//去掉字符串中的空格
jsonStr = jsonStr.replace(" ","");
//typeof https://www.cnblogs.com/liu-fei-fei/p/7715870.html
if(typeof jsonStr!='object'){
//去掉饭斜杠
jsonStr = jsonStr.replace(/\ufeff/g,"")
var jsonObj = JSON.parse(jsonStr)
that.booklist = jsonObj
}
}
if(data.code == 'fail'){
layer.msg(data.msg)
}
}
})
},
methods : {
addBook : function(event){
var that = this
layer.open({
type : 2,
title: 'add',
shadeClose: true,
shade: 0.8,
area: ['480px', '540px'],
content: "{:U('Index/add')}" ,//iframe的url
success : function(layero,index){
var submit = layer.getChildFrame('#submit',index);
submit.click(function(){
var book_id = layer.getChildFrame('#book_id',index).val();
var ISBN = layer.getChildFrame('#ISBN',index).val();
var title = layer.getChildFrame('#title',index).val();
var author = layer.getChildFrame('#author',index).val();
var theme = layer.getChildFrame('#theme',index).val();
var category = layer.getChildFrame('#category',index).val();
var abstract = layer.getChildFrame('#abstract',index).val();
var publisher = layer.getChildFrame('#publisher',index).val();
var pub_date = layer.getChildFrame('#pub_date',index).val();
var language = layer.getChildFrame('#language',index).val();
$.ajax({
url : "{:U('Index/addBook')}",
type : "post",
contentType : "application/x-www-form-urlencoded;charset=utf-8",
data : {
book_id : book_id,
ISBN : ISBN,
title : title,
author : author,
theme : theme,
category : category,
abstract : abstract,
publisher : publisher,
pub_date : pub_date,
language : language,
},
dataType : "json",
success : function(data){
if(data.code == 'success'){
layer.close(layer.index)
//将json字符串转为json对象
var arr = [
{
book_id : book_id,
isbn : ISBN,
title : title,
author : author,
theme : theme,
category : category,
abstract : abstract,
publisher : publisher,
pub_date : pub_date,
language : language,
}
]
var jsonStr = JSON.stringify(arr)
//去掉字符串中的空格
jsonStr = jsonStr.replace(" ","")
//typeof https://www.cnblogs.com/liu-fei-fei/p/7715870.html
if(typeof jsonStr!='object'){
//去掉饭斜杠
jsonStr = jsonStr.replace(/\ufeff/g,"")
var jsonObj = JSON.parse(jsonStr)
that.booklist.unshift(jsonObj[0])
}
layer.msg(data.msg)
}
if(data.code == 'fail'){
layer.close(layer.index)
layer.msg(data.msg)
}
}
})
})
}
})
},
removeBook : function(index){
var that = this
var book_id = that.booklist[index].book_id
$.ajax({
url : "{:U('Index/removeBook')}",
type : "post",
contentType : "application/x-www-form-urlencoded;charset=utf-8",
data : {
book_id : book_id
},
dataType : "json",
success : function(data){
if(data.code == 'success'){
that.booklist.splice(index,1)
layer.msg(data.msg)
}
if(data.code == 'fail'){
layer.msg(data.msg)
}
}
})
},
}
说明三点:
1、这里添加的时候,加入了一个layer的弹窗,这个可以忽略,我想强调的是,添加和删除一本书的瘦,不要再$.ajax的success回调函数中使用jQuery的dom操作来做前端的展示效果,善用js数组对象的方法,比如unshift()、push()、splice()等方法来对数据做处理,然后使用vue的数据绑定帮助你做视图的更新,有关js数组方法看下面:
http://www.w3school.com.cn/jsref/jsref_obj_array.asp
2、去了解以下vue实例的生命周期和对应的钩子函数的概念,这对于首屏加载和初始化参数很有用
3、注意到我v-for的写法:<tr v-for="(book,index) in booklist">
,这里的index,是指当前数组的下标,这里是为了标识你的remove点击事件的对象或者说是标识你要删除数组中的哪一项,笔者这里也表示困惑,因为之前开发小程序,有dataset这样的自定义属性,可以在methods的方法中获取原生事件的target或者currenttarget属性从而判断当前数组的下标,但是vue中并不知道如何获取到原生事件的属性,这个我在研究学习一下,后期更新…
ThinkPHP3.2.3
这个不再这里详述,中文的官方文档很详实,本次大家不用学习全部的框架知识,只需要有一定的PHP基本语法基础就好,我已经搭好框架,按照我写的接口,写相应的函数就好了
举个例子:
/*
* searchBook
* http://localhost/libSys/index.php?s=/Home/Index/searchBook 或者使用tp模板路由 {:U('Home/Index/searchBook')}
* {
* text [ISBN/title]
* }
* {
* code : "success" / "fail"
* data : {
* book_id [图书唯一码]
* ISBN
* title
* author
* theme
* category
* abstract
* publisher
* pub_date
* language [使用国际标准语言缩写,如中国=>zh_CN]
* }
* }
*/
public function searchBook(){
if(cookie('staffAccount') != ''){
$text = $_POST['text'];
$return = array();
$book = D('Book');
if(is_numeric($text) && strlen($text)==13){
//ISBN
$sql = "select * from lib_book where ISBN='{$text}' ";
$return = $book->query($sql);
}else{
//title
$text = '%'.$text.'%';
$sql = "select * from lib_book where title like '{$text}' ";
$return = $book->query($sql);
}
if($return){
$json = json_encode(array(
'code' => 'success',
'data' => json_encode($return)
));
echo $json;
}else{
$json = json_encode(array(
'code' => 'fail',
'msg' => '查询sql出错'
));
}
}else{
$json = json_encode(array(
'code' => 'fail',
'msg' => 'cookie过期'
));
echo $json;
}
}
说明三点:
1、返回数据格式必须为json,这个php的json_encode给我们提供了方便,我们直接去格式化PHP数组就可转为json数据包,返回的json格式尽量和我保持一致,code字段表示的状态,msg表示的是对应的提示信息,data则是需要展示的数据包
2、注释部分就是我写的接口,从上到下依次是,函数名,访问接口,需要的POST参数列表,返回的json参数列表
3、关于D方法,这个方法是实例化数据库中的一张表,例如D(‘Book’),是去实例化lib_book这个表,lib_
前缀字段我已经配置好了,若想去做数据库访问操作,直接D方法
对应的数据库表名的后半段就行了,再举个例子比如实例化lib_vipvard
这张表,只需D(‘Vipcard’),注意首字母大写;另外,query()方法去执行select查询语句,execute()去执行update、insert、delete更新语句