【php】利用原生态的JavaScript Ajax为php进行MVC分层设计,兼容IE6

MVC只是一种设计模式而已,一度被认为Model 1,也就是服务器语句与HTML语句杂糅的php,其实不用任何框架,仅仅利用原生态的JavaScript Ajax也可以对其进行MVC设计。由于什么都没有用,因此对IE6的兼容性是非常强的。还是《【php】数据库的增删改查和php与javascript之间的交互》(点击打开链接)那个页面的,对数据库增删改查的内容,希望各位能推广到整个网站。

一、基本目标

整个网页实现效果如下,用户输入完表单马上就有效果。

二、基本思想

首先,在test数据库中有一张这样的用户信息表,建表的时候注意检查一下那些数据库字段的编码是否是utf-8,一些Mysql在安装时候没有改默认的编码latin1的,不然一会儿你打死无法存中文。

然后,整个网页工程结构如下图:

在view.php中网页中不进行任何刷新,利用原生态的JavaScript Ajax,直接完成V-C层的交互。C-M层的交互通过include语句,引入M层的业务逻辑类中方法,通过类参数的传递完成。

同时,C、M层的php拒绝直接输入网址访问。这里不像JSP或者ASP,C层、M层都是编译之后的JAVA文件或者C#文件,根本就访问不了。我们还要对其进行保护。

三、制作过程

1、View层就一个简单的View.php,其布局如下,没什么好说的,非常简单的HTML布局。同时,注意,本页面:

(1)没有设置表单,所有表单提交的动作,通过button触发相应的JavaScript而触发。

(2)各个组件的ID,一会儿在JavaScript用到。其中用户信息表、修改ID的下拉框都是通过下面的脚本Ajax而加载的。

(3)布局中,包括一会儿的脚本在内没有任何php代码,便于各位布局。你把后缀名改成.html也能够正常运行。什么叫做真正的View层?这就是了,没有任何的服务器代码。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>用户信息表</title>
</head>

<body>
用户信息表如下:<div id="result"></div>
<hr />
插入数据<br />
用户名:<input type="text" name="username" />
密码:<input type="text" name="password" />
<button onclick="insert()">GO!</button>
<hr />
修改数据<br />
<select id="userid" name="userid"></select>
<select name="rowname">
    <option value="username">用户名</option>
    <option value="password">密码</option>
</select>
<input type="text" name="rowtext" />
<button onclick="update()">GO!</button>

</body>
</html>

其实整个View层的精髓在于下面的JavaScript脚本。View层就无须使用到Xajax这个插件了,《【php】Xajax Helloworld》(点击打开链接)。直接用原生态的JavaScript写。虽然代码量比起JQuery等前端框架较多,记住不容易。从建立Ajax对象,设置Ajax请求头,处理Ajax文本都要自己写,但在开发过程中,只是复制粘贴而已。因此可以观察到,所有的Ajax交互函数都大同小易。拿ForAllUserInfo();这个函数来重点说明怎么V-C层怎么通过Ajax交互。

<script>
//首先,本页面一加载就调用两个函数,加载本页。
ForAllUserInfo();
ForTotal();

//创建Ajax对象,不同浏览器有不同的创建方法,其实本函数就是一个简单的new语句而已。
function createXMLHttpRequest(XMLHttpRequest){
	var XMLHttpRequest;
	if(window.XMLHttpRequest){
		XMLHttpRequest=new XMLHttpRequest();
	}
	else if(window.ActiveXObject){
		try{
			XMLHttpRequest=new ActiveXObject("Msxml2.XMLHTTP");
		}
		catch(e){
			XMLHttpRequest=new ActiveXObject("Microsoft.XMLHTTP");
		}
	}
	return XMLHttpRequest;
}

function ForAllUserInfo(){
	var XMLHttpRequest=createXMLHttpRequest(XMLHttpRequest);
	//指明相应页面
	var url="dbselect.php";
	XMLHttpRequest.open("POST",url,true);
	//这里没法解释,你所有JavaScript的请求头都这样写就对了,不会乱码
	XMLHttpRequest.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
	//对于dbselect.php,本view.php没有任何参数给你。
	XMLHttpRequest.send(null);
	//对于返回结果怎么处理的问题
	XMLHttpRequest.onreadystatechange=function(){
		//这个4代表已经发送完毕之后
		if(XMLHttpRequest.readyState==4){
			//200代表正确收到了返回结果
			if(XMLHttpRequest.status==200){
				//那么id为result的div,就是整个dbselect.php页面了。
				document.getElementById("result").innerHTML=XMLHttpRequest.responseText;
			}
			else{
				//如果不能正常接受结果,你肯定是断网,或者我的服务器关掉了。
				alert("网络连接中断!");
			}
		}
	};
}

function ForTotal(){
	var XMLHttpRequest=createXMLHttpRequest(XMLHttpRequest);
	var url="dbtotal.php";
	XMLHttpRequest.open("POST",url,true);
	XMLHttpRequest.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
	XMLHttpRequest.send(null);
	XMLHttpRequest.onreadystatechange=function(){
		if(XMLHttpRequest.readyState==4){
			if(XMLHttpRequest.status==200){
				var total=parseInt(XMLHttpRequest.responseText);
				//先把修改ID的下拉列表清空
				document.getElementById("userid").innerHTML="";
				if(total>0){
					for(var i=1;i<total+1;i++){
						//javascript增加节点过程,数据库有多少项就填充多少个ID给用户修改。
						var selectnode=document.createElement("option");
						selectnode.value=i;
						selectnode.innerHTML=i;
						document.getElementById("userid").appendChild(selectnode);
					}
				}
			}
			else{
				alert("网络连接中断!");
			}
		}
	};
}

function insert(){
	//从输入框拿来插入数据的所有表单
	var username=document.getElementById("username").value;
	var password=document.getElementById("password").value;
	//如果用户输入的值不为空,则执行Ajax
	if(username!=""&&password!=""){
		var XMLHttpRequest=createXMLHttpRequest(XMLHttpRequest);
		var url="dbinsert.php";
		XMLHttpRequest.open("POST",url,true);
		XMLHttpRequest.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
		//这里View层的View.php需要发送两个参数给Controll层的dbinsert.php处理
		XMLHttpRequest.send("username="+username+"&password="+password);
		XMLHttpRequest.onreadystatechange=function(){
			if(XMLHttpRequest.readyState==4){
				if(XMLHttpRequest.status==200){
					//添加数据成功,则部分刷新View层的用户信息表与修改ID的下拉列表
					ForAllUserInfo();
					ForTotal();
				}
				else{
					alert("网络连接中断!");
				}
			}
		};
	}
	else{
		alert("不得为空!");
	}
}

//这里修改数据与insert()同理
function update(){
	var userid=document.getElementById("userid").value;
	var rowname=document.getElementById("rowname").value;
	var rowtext=document.getElementById("rowtext").value;
	if(userid!=""&&rowname!=""&&rowtext!=""){
		var XMLHttpRequest=createXMLHttpRequest(XMLHttpRequest);
		var url="dbupdate.php";
		XMLHttpRequest.open("POST",url,true);
		XMLHttpRequest.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
		XMLHttpRequest.send("userid="+userid+"&rowname="+rowname+"&rowtext="+rowtext);
		XMLHttpRequest.onreadystatechange=function(){
			if(XMLHttpRequest.readyState==4){
				if(XMLHttpRequest.status==200){
					ForAllUserInfo();
					ForTotal();
				}
				else{
					alert("网络连接中断!");
				}
			}
		};
	}
	else{
		alert("不得为空!");
	}
}

</script>

2、Controll层

Controll层的页面都与View层中的JavaScript函数一一对应。

比如dbupdate.php就对应view.php中的update()函数。通过如下两句对应起来。

var url="dbupdate.php";
XMLHttpRequest.open("POST",url,true);

(1)dbupdate.php

非常简单的页面,拿到前端送过来的两个数据,则进行与Model层的交互,完成数据库的操作。修改数据库,数据库是不会返回任何结果的,因此也没有什么数据给前端的。如果拿不到前端送过来的参数,那一定是恶意用户,通过输入网址非正常打开此页。C层M层一般是不给你打开的。

<?php
	include_once("db.php");
	if(empty($_REQUEST["userid"])){
		header("Content-type: text/html; charset=utf-8");
		echo "请正常打开此页!";
	}
	else{
		$db=new db();
		$userid=$_REQUEST["userid"];
		$rowname=$_REQUEST["rowname"];
		$rowtext=$_REQUEST["rowtext"];
		$db->modify("update user set ".$rowname."='".$rowtext."' where id=".$userid.";");
	}
?>

(2)dbinsert.php

插入数据同样的道理了,不再赘述。对应于前端的insert()函数

<?php
	include_once("db.php");
	if(empty($_REQUEST["username"])){
		header("Content-type: text/html; charset=utf-8");
		echo "请正常打开此页!";
	}
	else{
		$db=new db();
		$username=$_REQUEST["username"];
		$password=$_REQUEST["password"];
		$db->modify("insert into user(username,password) values ('".$username."','".$password."');");
	}

?>

(3)dbtotal.php

这一页是用来查询数据库有多少条结果,我们在修改数据的下拉列表就要提供给用户多少个ID,给用户指定修改。

对应于view.php中的ForTotal()函数。这一页是有返回结果的。因此dbtotal.php就把这个结果用echo打印出来,前端通过:

var total=parseInt(XMLHttpRequest.responseText);

这一句中的XMLHttpRequest.responseText拿到,前端的JavaScript必须强制指明这是数字,否则则出现7+1=71的神运算。JavaScript把数字当字符串了,也没办法了,毕竟所有变量都是var。php则都是美元$。

这一页就无须保护了,毕竟肯定要给用户看的。

<?php
	include_once("db.php");
	$db=new db();
	$total=$db->getTotal();
	echo $total;
?>

(4)dbselect.php

这一页其实和dbtotal.php一样,不过变成了构造一个表格,送给前端View.php的ForAllUserInfo()。ForAllUserInfo()得到的数据其实一段HTML文本,直接通过.innerHTML放上去就可以了。

<?php
	include_once("db.php");
	$db=new db();
	$user=$db->getAllUserInfo();
?>
<table border="1">
<tr><th>ID</th><th>用户名</th><th>密码</th></tr>
<?php
	for($i=0;$i<count($user);$i++){
		echo "<tr><td>".$user[$i]['id']."</td><td>".$user[$i]['username']."</td><td>".$user[$i]['password']."</td></tr>";
	}
?>
</table>

这页有HTML打死都不能与PHP代码混在一起的强迫症患者,请自行把所有HTML的代码,给成echo输出,反正我就只能给出这样的一个方案了。

3、Model层

这一层的所有方法都与C层的页面存在对应关系。

首先都公用一个数据库连接函数。之后各自在方法中调用,最后各自查询完毕则关闭这个连接。

然后,可以注意到上面的Controll层的dbupdate.php与dbinsert.php公用此类的一个方法。这主要是考虑到,都是传递一个SQL语句过来,然后没有返回结果,因此可以合在一起了。而查询数据库的所有数据与查询数据库的数据数量的返回结果是不同的,因此分开两个方法。

<?php
function createCon(){
	//数据库的地址是localhost:3306,数据库用户名(第二项)是root,数据库密码(第三项)是root
	$con=mysql_connect("localhost","root","root");
	if(!$con){
		die("连接失败!");
	}
	//要操作test数据库
	mysql_select_db("test",$con);
	//防止乱码
	mysql_query("set names utf8;");
	return $con;
}
class db{
	public function getAllUserInfo(){
		$con=createCon();
		$result=mysql_query("select * from user;");
		//如果查询的结果多,就放到一个二维数组里面,返回给Controll层
		//Controll层再对这个二维数组一一处理。
		//起始这个二维数组不就相当于JSP中的ArrayList吗?^_^
		$userList=array();
		for($i=0;$row=mysql_fetch_array($result);$i++){
			$userList[$i]['id']=$row['id'];
			$userList[$i]['username']=$row['username'];
			$userList[$i]['password']=$row['password'];
		}
		mysql_close($con);
		return $userList;
	}
	public function getTotal(){
		$con=createCon();
		$result=mysql_query("select count(*) as total from user;");
		//如果返回结果只有一个,那就直接这样取数据。
		$row=mysql_fetch_array($result);
		mysql_close($con);
		return $row['total'];
	}
	public function modify($sql){
		//对于那些传sql过来没有返回结果的方法,归纳到同一类
		$con=createCon();
		mysql_query($sql);
		mysql_close($con);
	}
}
?>

四、总结与展望

上面的制作过程最好合在一起看,反正我只能这样分层贴了。V-C,C-M一直在交互,从未被割裂,根本停不下来。对比与《【php】数据库的增删改查和php与javascript之间的交互》(点击打开链接)这个以MODEL1模式创作的工程,页面虽然增多,但是模块更加地清晰。

反正MVC仅仅是一种设计模式、设计思想而已,在PHP同样也能够实现。在JSP对这种模式的吹嘘是言过其实了,主要是JSP的部分创作者,不停地对于框架的使用,而忘记了这门语言的本质。

我觉得这个例子,再次证明了语言只是思想表达的载体。无插件无框架,纯HTML+CSS与纯JavaScript加PHP就能够实现,兼容IE6。如果你打包一样,放上防注入函数,完全可以成为自己的框架的。

对比与JSP与ASP,我在写PHP的时候更加舒服,告别了MyEclipse/Eclipse与Visual Studio的卡爆,用着早已被批得一毛不是Dreamwaver,甚至还可以用记事本写着网页,半点不卡。一台垃圾配置的Winxp就能够创造出好的网站。关键是你的语言基本功问题了。少做点喷子,多做点工程。多接触几门编程语言。

时间: 2024-10-05 07:24:20

【php】利用原生态的JavaScript Ajax为php进行MVC分层设计,兼容IE6的相关文章

利用setTimeoutc处理javascript ajax请求超时

用过jquery的人都知道里面的$.ajax能设置超时处理及各种错误的抛出,确实好用.原生的js没有对应的方法,还得写各种兼容.在实际运用中,不管请求是否成功都应该做容错处理, 不然用户不知道到底发生了什么,体验非常不好.超时就是一种情况,不可能请求失败了还让用户在那傻傻等待,是谁都受不了.下面就介绍一下用setTimeout来实现请求的超时处理. function createXMLHttpRequest() { var request = false; if(window.XMLHttpRe

【JavaScript】利用sort()函数与文件碎片实现表格的前端排序,兼容IE6原生态

表格排序在网页的应用也很多,尤其是一些信息系统输出一个密密麻麻的表格给人看,客户肯定会提出表格排序的要求.很多人定式思维地认为表格的排序一定要通过数据库后端进行交互,使用带order by asc/desc的语句去实现,然后再利用ajax似乎很完美似得.其实根本就不用与数据库打交道.在前端给出任意一个表格,都能够利用sort()函数与文件碎片实现表格的前端排序.在jquery里面是有一个advanceTable的插件做这件事,但是这个插件相当不好的是什么呢?与平常的插件一样,代码写得天花龙凤,没

利用CSS、JavaScript及Ajax实现图片预加载的三大方法

原文:3 Ways to Preload Images with CSS, JavaScript, or Ajax 译文:利用CSS.JavaScript及Ajax实现图片预加载的三大方法 预加载图片是提高用户体验的一个很好方法.图片预先加载到浏览器中,访问者便可顺利地在你的网站上冲浪,并享受到极快的加载速度.这对图片画廊及图片占据很大比例的网站来说十分有利,它保证了图片快速.无缝地发布,也可帮助用户在浏览你网站内容时获得更好的用户体验.本文将分享三个不同的预加载技术,来增强网站的性能与可用性.

解如何利用 XML 和 JavaScript Object Notation 在 Ajax 客户端和 Java 服务器之间传输数据。

2006 年 6 月发表 Ajax 核心 API(即所谓的 XMLHttpRequest)的唯一用途就是发送 HTTP 请求,在 Web 浏览器与服务器之间进行数据交换.Web 页面中运行的 JavaScript 代码,可以使用 XMLHttpRequest 将该请求参数提交至服务器端脚本,例如 Servlet 或 JSP 页面.调用的 Servlet/JSP 将发回一个响应,其中包含了一般用于不需刷新整个页面即可更新用户查看内容的数据.此种方法在性能和可用性方面均体现出了独有的优势,因为这将降

【JavaScript】利用onmousemove与onmouseout事件制作兼容IE6纯javascript无插件原生态的下拉菜单dropdown

下拉菜单dropdown在很多前端框架里面都有,直接拿来用就可以的,但是框架内的下拉菜单不好改,也很可能会有兼容性问题. 其实这东西完全可以利用HTML+CSS+Javascript去实现的. 效果如下: 其基本制作思想如下: 首先是HTML与CSS的布局,先布置一个table,这个table里面有两行,一行放下拉按钮,一行放下拉菜单,占据整个宽度的100%,单元格之间的行距为0. 因为共5个元素每列占20%. 这里不用div的float去布局,是因为这里使用table的话,这个下拉菜单组非常好

[转]利用CSS、JavaScript及Ajax实现图片预加载的三大方法

Perishable Press网站近日发表了一篇文章<3 Ways to Preload Images with CSS, JavaScript, or Ajax>,分享了利用CSS.JavaScript及Ajax实现图片预加载的三大方法.下面为译文. 预加载图片是提高用户体验的一个很好方法.图片预先加载到浏览器中,访问者便可顺利地在你的网站上冲浪,并享受到极快的加载速度.这对图片画廊及图 片占据很大比例的网站来说十分有利,它保证了图片快速.无缝地发布,也可帮助用户在浏览你网站内容时获得更好

【JavaScript】原生态兼容IE6的图片轮播

<[Bootstrap]图片轮播组件Carousel>(点击打开链接)虽然做得很不错,但是由于只兼容到IE8,所以没有用的.其实原生态兼容IE6的图片轮播并没有想象中的那么难,网上的很多兼容IE6的图片轮播其实代码写得很糟糕的.首先复用性很差,根本就不知道怎么修改,然后加入了很多如同百叶窗这些可有可无的特效,把原本简短的代码弄得很差,最后,这些东西还直接用JavaScript创建组件来显示自己的Javascript学得有多么地强大,然后又不好好教别人怎么做,直接用一个JS写完整个网页个人觉得相

【JavaScript】利用文件碎片DocumentFragment改进兼容IE6可调可控的图片滑块

上次在<[JavaScript]兼容IE6可调可控的图片滑块>(点击打开链接)的算法写得很不好,如果你要做N个图片的图片滑块,每次显示X张图片,则要一次性地多加载X-1张图片,还要用一种显示框移动的方法去实现.更可怕的是,还要理所当然地认为就是这样的.虽然这个违背常人思维方式在网上广泛流传,而且好像还是公式一样,就只有一种实现方法,其实不是的,明显可以利用文件碎片DocumentFragment去实现图片滑块,如果你要N个图片的图片滑块,就加载N个图片,这才是正常的.关键利用文件碎片,实现20

JavaScript Ajax 与服务器通信

XMLHttpRequest对象 -常用方法-: open("method","URL",是否异步默认为true,"用户名","密码") 设置进行异步请求目标的URL send(content); content可以是DOM对象的实例.输入流.字符串.null setRequestHeader("header","value") 为请求的HTTP头设置值 abort() 停止或放弃当前异