首頁 後端開發 php教程 【php】利用原生态的JavaScript Ajax为php进行MVC分层设计,兼容IE6

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

Jun 23, 2016 pm 01:37 PM

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层?这就是了,没有任何的服务器代码。

<meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>用户信息表</title>用户信息表如下:<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>
登入後複製

其实整个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();?>
登入後複製
"; }?>
ID 用户名 密码
".$user[$i]['id']." ".$user[$i]['username']." ".$user[$i]['password']."

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


3、Model层

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

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

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

<?phpfunction 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就能够创造出好的网站。关键是你的语言基本功问题了。少做点喷子,多做点工程。多接触几门编程语言。

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

在PHP API中說明JSON Web令牌(JWT)及其用例。 在PHP API中說明JSON Web令牌(JWT)及其用例。 Apr 05, 2025 am 12:04 AM

JWT是一種基於JSON的開放標準,用於在各方之間安全地傳輸信息,主要用於身份驗證和信息交換。 1.JWT由Header、Payload和Signature三部分組成。 2.JWT的工作原理包括生成JWT、驗證JWT和解析Payload三個步驟。 3.在PHP中使用JWT進行身份驗證時,可以生成和驗證JWT,並在高級用法中包含用戶角色和權限信息。 4.常見錯誤包括簽名驗證失敗、令牌過期和Payload過大,調試技巧包括使用調試工具和日誌記錄。 5.性能優化和最佳實踐包括使用合適的簽名算法、合理設置有效期、

會話如何劫持工作,如何在PHP中減輕它? 會話如何劫持工作,如何在PHP中減輕它? Apr 06, 2025 am 12:02 AM

會話劫持可以通過以下步驟實現:1.獲取會話ID,2.使用會話ID,3.保持會話活躍。在PHP中防範會話劫持的方法包括:1.使用session_regenerate_id()函數重新生成會話ID,2.通過數據庫存儲會話數據,3.確保所有會話數據通過HTTPS傳輸。

描述紮實的原則及其如何應用於PHP的開發。 描述紮實的原則及其如何應用於PHP的開發。 Apr 03, 2025 am 12:04 AM

SOLID原則在PHP開發中的應用包括:1.單一職責原則(SRP):每個類只負責一個功能。 2.開閉原則(OCP):通過擴展而非修改實現變化。 3.里氏替換原則(LSP):子類可替換基類而不影響程序正確性。 4.接口隔離原則(ISP):使用細粒度接口避免依賴不使用的方法。 5.依賴倒置原則(DIP):高低層次模塊都依賴於抽象,通過依賴注入實現。

在PHPStorm中如何進行CLI模式的調試? 在PHPStorm中如何進行CLI模式的調試? Apr 01, 2025 pm 02:57 PM

在PHPStorm中如何進行CLI模式的調試?在使用PHPStorm進行開發時,有時我們需要在命令行界面(CLI)模式下調試PHP�...

PHP 8.1中的枚舉(枚舉)是什麼? PHP 8.1中的枚舉(枚舉)是什麼? Apr 03, 2025 am 12:05 AM

PHP8.1中的枚舉功能通過定義命名常量增強了代碼的清晰度和類型安全性。 1)枚舉可以是整數、字符串或對象,提高了代碼可讀性和類型安全性。 2)枚舉基於類,支持面向對象特性,如遍歷和反射。 3)枚舉可用於比較和賦值,確保類型安全。 4)枚舉支持添加方法,實現複雜邏輯。 5)嚴格類型檢查和錯誤處理可避免常見錯誤。 6)枚舉減少魔法值,提升可維護性,但需注意性能優化。

如何在系統重啟後自動設置unixsocket的權限? 如何在系統重啟後自動設置unixsocket的權限? Mar 31, 2025 pm 11:54 PM

如何在系統重啟後自動設置unixsocket的權限每次系統重啟後,我們都需要執行以下命令來修改unixsocket的權限:sudo...

解釋PHP中的晚期靜態綁定(靜態::)。 解釋PHP中的晚期靜態綁定(靜態::)。 Apr 03, 2025 am 12:04 AM

靜態綁定(static::)在PHP中實現晚期靜態綁定(LSB),允許在靜態上下文中引用調用類而非定義類。 1)解析過程在運行時進行,2)在繼承關係中向上查找調用類,3)可能帶來性能開銷。

See all articles