Heim > Web-Frontend > js-Tutorial > Hauptteil

Nodejs und Express bauen einen Chatraum für mehrere Personen auf

小云云
Freigeben: 2018-02-22 09:48:51
Original
1634 Leute haben es durchsucht

Vorbereitung: Erstellen Sie einen neuen Chatroom-Ordner und geben Sie den folgenden Befehl in das Terminal ein. (Wenn Sie ihn nicht installiert haben, gehen Sie zur offiziellen Website, um node und npm zu installieren.) automatisch für Sie generiert

Installation Express und socket.io

Die package.json-Datei lautet wie folgt:


//package.json
{
 "name": "chatroom",
 "version": "1.0.0",
 "description": "A simple chatroom",
 "main": "index.js",
 "scripts": {
  "test": "echo \"Error: no test specified\" && exit 1"
 },
 "repository": {
  "type": "git",
  "url": "git+https://github.com/ddvdd008/chatroom.git"
 },
 "keywords": [
  "chatroom",
  "nodejs",
  "express"
 ],
 "author": "ddvdd",
 "license": "ISC",
 "bugs": {
  "url": "https://github.com/ddvdd008/chatroom/issues"
 },
 "homepage": "https://github.com/ddvdd008/chatroom#readme"
}
Nach dem Login kopieren

Express und socket.io installieren


npm install express --save 
npm install socket.io --save
Nach dem Login kopieren

package.json fügt automatisch Abhängigkeiten hinzu


"dependencies": {
 "express": "^4.16.2",
 "socket.io": "^2.0.4"
}
Nach dem Login kopieren

weil Wir verwenden das Express-Framework zum Schreiben von Back-End-Diensten und verwenden socket.io (Socket.io ist eigentlich der übergeordnete Satz von WebSocket. Socket.io kapselt Methoden wie WebSocket und Abfragen werden je nach Situation Kommunikationsmethoden auswählen.) Der Client und der Server stellen eine dauerhafte Verbindung her, um die Kommunikation zu erleichtern.

Die Vorbereitungsarbeiten sind hier fast abgeschlossen, beginnen wir Schritt für Schritt mit der Umsetzung.

Erstellen Sie einen Webserver

Express-Erstellungsdienst

Studenten, die Knoten gelernt haben, sollten damit vertraut sein Verwenden Sie http.createServer. Erstellen Sie einfach einen Server. Dieses Mal verwenden wir Express, um den Dienst zu erstellen. Erstellen Sie eine app.js im Stammverzeichnis des Projekts.


/**
* Created by ddvdd on 2018-02-07.
*/
const express = require('express'); 
const app = express();    // 创建express实例,赋值给app。
const fs = require('fs');   // 这个是node的文件读取模块,用于读取文件
const path = require('path');  // 这是node的路径处理模块,可以格式化路径

app.listen(3000,()=>{    
 console.log("server running at 127.0.0.1:3000");  // 代表监听3000端口,然后执行回调函数在控制台输出。
});

/**
* app.get(): express中的一个中间件,用于匹配get请求,说的简单点就是node处理请求的路由,对于不同url请求,让对应的不同app.get()去处理
* '/': 它匹配get请求的根路由 '/'也就是 127.0.0.1:3000/就匹配到它了
* req带表浏览器的请求对象,res代表服务器的返回对象
*/
app.get('/',(req,res)=>{
 res.redirect('/chat.html');  // express的重定向函数。如果浏览器请求了根路由'/',浏览器就给他重定向到 '127.0.0.1:3000/chat.html'路由中
});


/**
* 这里匹配到的是/chat.html就是上面重定向到的路径。
*/
app.get('/chat.html',(req,res)=>{
 fs.readFile(path.join(__dirname,'./public/chat.html'),function(err,data){  //读取文件,readFile里传入的是文件路径和回调函数,这里用path.join()格式化了路径。
  if(err){
   console.error("读取chat.html发生错误",err);     //错误处理
   res.send('4 0 4');           //如果发生错误,向浏览器返回404
  } else {
   res.end(data);     //这里的data就是回调函数的参数,在readFile内部已经将读取的数据传递给了回调函数的data变量。
  }         //我们将data传到浏览器,就是把html文件传给浏览器
 })
});
Nach dem Login kopieren

Nachdem Sie es gelesen haben, werden Sie sagen, dass das Express-Framework nicht so einfach zu sein scheint. Die einfachste Methode zum Senden einer einzelnen Seite ist dieselbe wie die von Node Der eigene http .createServer ist nicht viel anders und ziemlich problematisch. Aus heutiger Sicht ist dies tatsächlich nicht der Fall, damit Sie es leichter verstehen. Express bietet eine sehr leistungsstarke Middleware, die uns beim Hosten statischer Ressourcendateien hilft:


app.use('/',express.static(path.join(__dirname,'./public'))); //一句话就搞定。
Nach dem Login kopieren

anstelle des Originals:


app.get('/chat.html',(req,res)=>{
 fs.readFile(path.join(__dirname,'./public/chat.html'),function(err,data){  
  if(err){
   console.error("读取chat.html发生错误",err);     
   res.send('4 0 4');           
  } else {
   res.end(data);     
  }         
 })
});
Nach dem Login kopieren

__dirname stellt den absoluten Pfad dar, in dem sich die aktuelle Datei befindet, also Wir verwenden path.join, um app.js hinzuzufügen. Der absolute Pfad und die Öffentlichkeit werden addiert, um den absoluten Pfad der Öffentlichkeit zu erhalten. Path.join wird verwendet, um seltsame Pfade wie ././public zu vermeiden. express.static hilft uns, die statischen Ressourcen im öffentlichen Ordner zu hosten. Solange der Pfad 127.0.0.1:3000/XXX/AAA vorhanden ist, wird im öffentlichen Ordner nach der AAA-Datei im XXX-Ordner gesucht und diese dann an den Browser gesendet.

Jetzt wollen wir sehen, ob dieser Code sehr einführend ist. Schüler, die genau wissen, was app.use() tut, können hier klicken

Socket.io stellt eine Verbindung zwischen dem Client und dem Server her

Nachdem wir den oben genannten Dienst erstellt haben, müssen wir auf socket.io verweisen, damit Client und Server eine langfristige Verbindung herstellen können. Wir transformieren app.js wie folgt:


/**
* Created by ddvdd on 2018-02-07.
*/
const express = require('express'); 
const app = express();    // 创建express实例,赋值给app。
const server = require('http').Server(app); 
const io = require('socket.io')(server);  //将socket的监听加到app设置的模块里。这两句理解不了的可以去socket.io官网去看
const path = require('path');  // 这是node的路径处理模块,可以格式化路径

server.listen(3000,()=>{    
 console.log("server running at 127.0.0.1:3000");  // 代表监听3000端口,然后执行回调函数在控制台输出。 
}); 
...
...
app.use('/',express.static(path.join(__dirname,'./public')));  //一句话就搞定。 

/*socket*/ 
io.on('connection',(socket)=>{    //监听客户端的连接事件 
 
});
Nach dem Login kopieren

o.on bedeutet, auf ein bestimmtes Ereignis zu warten. Sobald das Ereignis eintritt, wird die Rückruffunktion ausgelöst. „Verbindung“ ist ein Ereignisname. Er wurde definiert und wird ausgelöst, solange der Benutzer verbunden ist. Nachdem app.js nun im Grunde fertig ist, führen wir es im Stammverzeichnis aus:

node app.js

>

Besuchen Sie jetzt http://127.0.0.1:3000/static/chat.html:

Hey? Nichts. . . Das ist kein Unsinn! Wir haben keine statischen Ressourcen, die URL-Anfragen entsprechen!

Statisches HTML hinzufügen

Wir erstellen einen öffentlichen Ordner im Stammverzeichnis des Projekts und erstellen eine neue chat.html-Datei im öffentlichen Ordner:


<!DOCTYPE html> 
<html lang="en"> 
<head> 
 <meta charset="UTF-8"> 
 <title>聊天室</title> 
</head> 
<body> 
这是我们的聊天室 
</body> 
</html>
Nach dem Login kopieren

Jetzt aktualisieren wir die Seite. Sie sehen, dass die Seite angezeigt wird:

>

Was wir hier haben, ist tatsächlich der einfachste Browser und das einfachste Web Server-Kollaborationsprojekt Es wurde abgeschlossen. Wir werden die Seite weiter verbessern und dem Server-Backend Geschäftsfunktionen hinzufügen, um einen Chatroom für mehrere Personen zu realisieren.

Grundlegende Funktionsimplementierung

Anmeldefunktion, wir benötigen einen Benutzernamen (kein Passwort erforderlich), der Benutzername muss auf dem Client-Server gespeichert werden. Bei jeder Übermittlung von Informationen müssen Sie grundsätzlich den Benutzernamen angeben, sonst wissen Sie nicht, wer die Informationen gesendet hat.

Gruppenchat-Funktion, wir müssen Informationen zwischen uns und anderen unterscheiden

Anmeldefunktionsimplementierung

Anmeldeseite Refactor

Die einfachste Anmeldeschnittstelle besteht aus einem Benutzernamen-Eingabefeld und einer Anmeldeschaltfläche:


//chat.html
<!DOCTYPE html> 
<html lang="en"> 
<head> 
<meta charset="UTF-8"> 
<title>聊天室</title>
<style>
 *{
  margin:0;
  padding:0;
  box-sizing: border-box;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
 }
 .container{
  position: absolute;
  top:0;
  left:0;
  right:0;
  bottom:0;
  background-color: grey;
  padding: 50px;
 }
 .container .title{
  width:300px;
  margin: 0 auto;
  font-size: 30px;
  font-family: &#39;Franklin Gothic Medium&#39;;
  font-weight: bold;
  text-align: center;
  margin-bottom:50px;
 }
 .container .login-wrap{
  width:400px;
  padding: 20px;
  border: 1px solid #000;
  margin: 0 auto;
  text-align: center;
 }
 .login-wrap .user-ipt{
  width:360px;
  text-align: center;
  vertical-align: middle;
 }
 .login-wrap .login-button{
  width:60px;
  height:24px;
  line-height:20px;
  font-size: 14px;
  padding: 2px 0;
  border-radius: 5px;
  margin-top:10px;
 }
</style> 
</head> 
<body> 
 <p class="container">
  <p class="title">欢迎来到ddvdd聊天室</p>
  <p class="login-wrap">
   <p class="user-ipt">
    <span class="user-name">用户名:</span>
    <input id="name" class="name-ipt" type="text" />
   </p>
   <button id="loginbutton" class="login-button">登陆</button>
  </p>
 </p>
</body> 
</html>
Nach dem Login kopieren

Einfacher Punktstil, The Die statische Seite ist fertig. Aktualisieren wir die Seite:

Interaktion auf der Anmeldeseite

Ich war gestern mit dem Schreiben zur Hälfte fertig Nachmittag. . . Die Abteilung muss plötzlich zu einer Teambuilding-Party gehen, sodass sie den Code nur in Eile einreichen und darüber hinwegkommen kann. Ich bin heute Morgen früh ins Unternehmen gekommen und habe weiter codiert.

Kommen wir ohne weitere Umschweife zum Punkt: Wenn ein Benutzer auf den Server zugreift und sich erfolgreich anmeldet, zählt dies als Anzahl Bei jeder Online-Anmeldung werden die Benutzerinformationen in einem Array gespeichert und auf dem Server gespeichert. Dabei ist zu beachten, dass der Server den angemeldeten Benutzernamen überprüft und das Überprüfungsergebnis zurückgibt an den Client. Der Client ändert, ob die aktuelle Seite über die Verifizierungs-Chat-Seite aufgerufen werden soll.

上面的服务器和客户端交互都是通过socket.io来实现通讯的,前端的业务交互我们这里就采用jquery来实现,在public文件夹下新建js文件夹,下载jquery-3.2.1.min.js、新建main.js。然后对chat.html引入需要的sdk:


<script src="js/jquery-3.2.1.min.js"></script>
<script src="js/main.js"></script>
//socket.io官网要求这么引入
<script src="/socket.io/socket.io.js"></script>
Nach dem Login kopieren

引入完sdk,我们对main的js添加登录功能:


//main.js
/**
* Created by ddvdd on 2018-02-08.
*/
$(function(){
 const url = &#39;http://127.0.0.1:3000&#39;;
 let _username = &#39;&#39;;
 let _$inputname = $(&#39;#name&#39;);
 let _$loginButton = $(&#39;#loginbutton&#39;);

 let socket = io.connect(url);

 //设置用户名,当用户登录的时候触发
 let setUsername = () => {
  
  _username = _$inputname.val().trim(); //得到输入框中用户输入的用户名

  //判断用户名是否存在
  if(_username) {
   socket.emit(&#39;login&#39;,{username: _username}); //如果用户名存在,就代表可以登录了,我们就触发登录事件,就相当于告诉服务器我们要登录了
  }
  else{
   alert(&#39;请输入用户名!&#39;);
  }
 };
 
 
 
 /*前端事件*/
 _$loginButton.on(&#39;click&#39;,function (event) { //监听按钮的点击事件,如果点击,就说明用户要登录,就执行setUsername函数
  setUsername();
 });

 /*socket.io部分逻辑*/ 
 socket.on(&#39;loginResult&#39;,(data)=>{ 
  /** 
  * 如果服务器返回的用户名和刚刚发送的相同的话,就登录 
  * 否则说明有地方出问题了,拒绝登录 
  */ 
  if(data.code === 0) { 
   // 登陆成功,切换至聊天室页面 
  }
  else if(data.code ===1){ 
   alert(&#39;用户已登录!&#39;); 
  }
  else{
   alert(&#39;登录失败!&#39;);
  }
 }) 

});
//app.js
/**
* Created by ddvdd on 2018-02-07.
*/
const express = require(&#39;express&#39;); 
const app = express();    // 创建express实例,赋值给app。
const server = require(&#39;http&#39;).Server(app); 
const io = require(&#39;socket.io&#39;)(server);  //将socket的监听加到app设置的模块里。这两句理解不了的可以去socket.io官网去看
const path = require(&#39;path&#39;);  // 这是node的路径处理模块,可以格式化路径

const users = [];     //用来保存所有的用户信息 
let usersNum = 0;     //统计在线登录人数

server.listen(3000,()=>{    
 console.log("server running at 127.0.0.1:3000");  // 代表监听3000端口,然后执行回调函数在控制台输出。 
}); 


/**
* app.get(): express中的一个中间件,用于匹配get请求,说的简单点就是node处理请求的路由,对于不同url请求,让对应的不同app.get()去处理
* &#39;/&#39;: 它匹配get请求的根路由 &#39;/&#39;也就是 127.0.0.1:3000/就匹配到它了
* req带表浏览器的请求对象,res代表服务器的返回对象
*/
app.get(&#39;/&#39;,(req,res)=>{
 res.redirect(&#39;/static/chat.html&#39;);  // express的重定向函数。如果浏览器请求了根路由&#39;/&#39;,浏览器就给他重定向到 &#39;127.0.0.1:3000/chat.html&#39;路由中
});

/** 
* __dirname表示当前文件所在的绝对路径,所以我们使用path.join将app.js的绝对路径和public加起来就得到了public的绝对路径。 
* 用path.join是为了避免出现 ././public 这种奇怪的路径 
* express.static就帮我们托管了public文件夹中的静态资源。 
* 只要有 127.0.0.1:3000/XXX/AAA 的路径都会去public文件夹下找XXX文件夹下的AAA文件然后发送给浏览器。 
*/ 
app.use(&#39;/static&#39;,express.static(path.join(__dirname,&#39;./public&#39;)));  //一句话就搞定。 

/*socket*/ 
io.on(&#39;connection&#39;,(socket)=>{    //监听客户端的连接事件 
 
 socket.on(&#39;login&#39;,(data)=>{ 

  if(checkUserName(data)){
   socket.emit(&#39;loginResult&#39;,{code:1}); //code=1 用户已登录 
  }
  else{
   //将该用户的信息存进数组中 
   users.push({ 
    username: data.username, 
    message: [] 
   }); 
   socket.emit(&#39;loginResult&#39;,{code:0}); //code=0 用户登录成功
   usersNum = users.length; 
   console.log(`用户${data.username}登录成功,进入ddvdd聊天室,当前在线登录人数:${usersNum}`); 
  }
  
 }); 

 //断开连接后做的事情 
 socket.on(&#39;disconnect&#39;,()=>{   //注意,该事件不需要自定义触发器,系统会自动调用 
  usersNum = users.length; 
  console.log(`当前在线登录人数:${usersNum}`); 
 }); 
}); 
//校验用户是否已经登录
const checkUserName = (data) => {
 let isExist = false;
 users.map((user) => {
  if(user.username === data.username){
   isExist = true;
  }
 });
 return isExist;
}
Nach dem Login kopieren

上面代码大家需要了解以下几点:

  1. socket.on 表示监听事件,后面接一个回调函数用来接收emit发出事件传递过来的对象。

  2. socket.emit 用来触发事件,传递对象给on监听事件。

  3. 我们socket连接之后的监听触发事件都要写在io.on('connection')的回调里面,因为这些事件都是连接之后发生的,就算是断开连接的事件 disconnect 也是在连接事件中发生的,没有正在连接的状态,哪来的断开连接呢?

  4. 理解虽然服务器端只有app.js一个文件,但是不同的客户端连接后信息是不同的,所以我们必须要将一些公用的信息,比如说,储存所有登录用户的数组,所有用户发送的所有信息存储在外部,一定不能存储在connecion里

效果展示:

群聊功能实现

写完简单的登录功能,现在我们来写这项目最重要的功能群聊。首先我们先来处理下页面,因为功能简单,所以不单独建立html来显示聊天室,就直接写在login页面,通过class名称的变化来切换登录后,聊天室的显示。

聊天室页面重构

下面我们对chat.html进行整改:


<!DOCTYPE html> 
<html lang="en"> 
<head> 
 <meta charset="UTF-8"> 
 <title>聊天室</title>
 <script src="js/jquery-3.2.1.min.js"></script> 
 <script src="js/main.js"></script> 
 <script src="/socket.io/socket.io.js"></script> 
 <style>
  *{
   margin:0;
   padding:0;
   box-sizing: border-box;
   -webkit-box-sizing: border-box;
   -moz-box-sizing: border-box;
  }
  .container{
   position: absolute;
   top:0;
   left:0;
   right:0;
   bottom:0;
   background-color: darkgrey;
   padding: 50px;
   overflow-y: scroll;
  }
  .container .title{
   margin: 0 auto;
   font-size: 30px;
   font-family: &#39;Franklin Gothic Medium&#39;;
   font-weight: bold;
   text-align: center;
   margin-bottom:20px;
  }
  .container .login-wrap{
   width:400px;
   padding: 20px;
   border: 1px solid #000;
   margin: 0 auto;
   text-align: center;
  }
  .login-wrap .user-ipt{
   width:360px;
   text-align: center;
   vertical-align: middle;
  }
  .login-wrap .login-button{
  width:60px;
  height:24px;
  line-height:20px;
  font-size: 14px;
  padding: 2px 0;
  border-radius: 5px;
  margin-top:10px;
  }
  .chat-wrap .chat-content{
   width:100%;
   height:600px;
   background-color: whitesmoke;
   padding:10px;
  }
  .chat-wrap .send-wrap{
   margin-top: 20px;
  }
  .message-ipt{
   width: 200px;
   height: 100px;
   padding: 0 5px;
   vertical-align: bottom;
  }
  .chat-content p{
   display: block;
   margin-bottom: 10px;
  }
  .chat-content p .msg{
   display: inline-block;
   padding: 8px 11px;
   border-radius:6px;
  }
  .chat-content .self-message .msg{
   background-color:#d0e7ff;
   border: 1px solid #c9dfff;
  }
  .chat-content .other-message .msg{
   background-color:white;
   border: 1px solid #eee;
  }
  .chat-content .self-message{
   text-align:right;
  }
  .chat-content .other-message{
   text-align-last:left;
  }
 </style> 
</head> 
<body> 
 <p class="container">
  <p id="loginbox" class="login-wrap">
   <p class="title">登录</p>
   <p class="user-ipt">
    <span class="user-name">用户名:</span>
    <input id="name" class="name-ipt" type="text" />
   </p>
   <button id="loginbutton" class="login-button">登录</button>
  </p>
  <p id="chatbox" class="chat-wrap" style="display:none">
   <p id="content" class="chat-content">
    <!-- 聊天内容 -->
   </p>
   <p class="send-wrap">
    <textarea rows="3" cols="20" id="chatmessage" class="message-ipt" type="textarea" placeholder="请输入要发送的信息内容"></textarea>
   </p>
  </p>
 </p>
</body> 
</html>
Nach dem Login kopieren

新增chatbox容器来作为聊天室,里面有一个群聊的聊天框,和一个发送消息的文本框。通过上面loginResult回调,对loginbox进行隐藏,显示chatbox:


//显示聊天室界面
let showChatRoom = () => {
 /** 
  * 1.隐藏登录框,取消它绑定的事件 
  * 2.显示聊天界面 
  */ 
 $(&#39;#loginbox&#39;).hide(&#39;slow&#39;);
 _$loginButton.off(&#39;click&#39;);
 /** 
 * 显示聊天界面,并显示一行文字,欢迎用户 
 */
 $(`<p class="title">欢迎${_username}来到ddvdd聊天室</p>`).insertBefore($("#content")); 
 $("#chatbox").show(&#39;slow&#39;);
}
Nach dem Login kopieren

消息事件发送监听机制

聊天一定是客户端触发的,所以发送信息是客户端触发,服务器监听。

服务器监听到发送信息的事件后会存储信息,然后触发发送信息成功事件广播给所有客户端,将信息传给所有客户端。

发送消息sendMessage事件


//main.js
//发送消息
let sendMessage = function () { 
 /** 
  * 得到输入框的聊天信息,如果不为空,就触发sendMessage 
  * 将信息和用户名发送过去 
  */ 
 let _message = _$chattextarea.val(); 
 
 if(_message) { 
  socket.emit(&#39;sendMessage&#39;,{username: _username, message: _message}); 
 }
 else{
  alert(&#39;请输入发送消息!&#39;);
 } 
}; 
...
/*聊天事件*/ 
_$chattextarea.on(&#39;keyup&#39;,function (event) { 
 if(event.keyCode === 13) { 
  sendMessage(); 
  _$chattextarea.val(&#39;&#39;); 
 } 
});
Nach dem Login kopieren

服务器端监听sendMessage事件


//app.js
/** 
 * 监听sendMessage,我们得到客户端传过来的data里的message,并存起来。 
 */ 
socket.on(&#39;sendMessage&#39;,(data)=>{ 
 for(let _user of users) { 
  if(_user.username === data.username) { 
   _user.message.push(data.message); 
   //信息存储之后触发receiveMessage将信息发给所有浏览器-广播事件 
   io.emit(&#39;receiveMessage&#39;,data); 
   break; 
  } 
 } 
});
Nach dem Login kopieren

我们是遍历服务器端的用户数组,找到该用户,将发送的信息存起来,然后触发receiveMessage事件广播到所有浏览器,sendMessage是写在connection里,login之外的,为什么这么做大家一定要理解,发送消息是连接时候做的事情,而不是登录时做的事情。

注意的是,我使用的是io.emit,他是真正的广播到所有浏览器,socket.broadcast.emit则不会广播到自己的浏览器。

客户端监听receiveMessage事件


//main.js
socket.on(&#39;receiveMessage&#39;,(data)=>{ 
 /** 
  * 
  * 监听服务器广播的消息
  */ 
 showMessage(data);
}) 
//显示消息
let showMessage = function (data) { 
 //先判断这个消息是不是自己发出的,然后再以不同的样式显示 
 if(data.username === _username){ 
  $("#content").append(`<p class=&#39;self-message&#39;><span class=&#39;msg&#39;>${data.message}</span><span class=&#39;name&#39;> :${data.username}</span></p>`); 
 }else { 
  $("#content").append(`<p class=&#39;other-message&#39;><span class=&#39;name&#39;>${data.username}: </span><span class=&#39;msg&#39;>${data.message}</span></p>`); 
 } 
};
Nach dem Login kopieren

写到这边,我们的聊天室基本功能已经完成了,来看看效果吧!打开三个浏览器,分别登录老大、老二、老三,发一句“大噶好~,我是渣渣辉!”。

相关推荐:

vue组件父子间通信实现聊天室实例详解

实例详解vue组件父子间通信之聊天室

用Node.js编写多人实时在线聊天室

Das obige ist der detaillierte Inhalt vonNodejs und Express bauen einen Chatraum für mehrere Personen auf. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!