零基础实现node+express个性化聊天室的示例

本篇文章使用node+express+jquery写一个个性化聊天室,一起来get一下~(源码地址见文章末尾)

效果图

项目结构

实现功能

  1. 登录检测
  2. 系统自动提示用户状态(进入/离开)
  3. 显示在线用户
  4. 支持发送和接收消息
  5. 自定义字体颜色
  6. 支持发送表情
  7. 支持发送图片

下面将一一讲解如何实现

前期准备

node及npm环境、expresssocket.io

具体实现

1、将聊天室部署到服务器

先用node搭建一个服务器,部署在localhost:3000端口,先尝试向浏览器发送一个“hello world”,新建server.js文件。

var app = require('express')(); // 引入express模块
var http = require('http').Server(app);

app.get('/', function(req, res){ // 路由为localhost:3000时向客户端响应“hello world”
 res.send('<h1>Hello world</h1>'); // 发送数据
});

http.listen(3000, function(){ // 监听3000端口
 console.log('listening on *:3000');
});

打开浏览器输入网址:localhost:3000是这样的

一个node服务器搭建成功。

接下来用express向浏览器返回一个html页面

#安装express模块
npm install --save express

将server.js的代码改一下:

var express = require('express');
var app = express();
var http = require('http').Server(app); 

// 路由为/默认www静态文件夹
app.use('/', express.static(__dirname + '/www'));

express.static(__dirname + '/www');是将www文件夹托管为静态资源,意味着这个文件夹里的文件(html、css、js)彼此可以用相对路径。在www文件夹中添加index.html文件以及相应的css(相应css代码就不贴了,详情见源码),如下,该页面用了font-awesome小图标

<!doctype html>
<html>
 <head>
 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width, initial-scale=1">
 <title>chat</title>
 <link rel="stylesheet" href="style/index.css" rel="external nofollow" >
 <link rel="stylesheet" href="style/font-awesome-4.7.0/css/font-awesome.min.css" rel="external nofollow" >
 </head>
 <body>
 <div class="all">
  <div class="name">
  <!-- <h2>请输入你的昵称</h2> -->
  <input type="text" id="name" placeholder="请输入昵称..." autocomplete="off">
  <button id="nameBtn">确 定</button>
  </div>
  <div class="main">
  <div class="header">
   <img src="image/logo.jpg">
   happy聊天室
  </div>
  <div id="container">
   <div class="conversation">
    <ul id="messages"></ul>
    <form action="">
     <div class="edit">
     <input type="color" id="color" value="#000000">
     <i title="双击取消选择" class="fa fa-smile-o" id="smile">
     </i><i title="双击取消选择" class="fa fa-picture-o" id="img"></i>
     <div class="selectBox">
      <div class="smile">
      </div>
      <div class="img">
      </div>
     </div>
     </div>
     <!-- autocomplete禁用自动完成功能 -->
     <textarea id="m"></textarea>
     <button class="btn rBtn" id="sub">发送</button>
     <button class="btn" id="clear">关闭</button>
    </form>
   </div>
   <div class="contacts">
   <h1>在线人员(<span id="num">0</span>)</h1>
   <ul id="users"></ul>
   <p>当前无人在线哟~</p>
   </div>
  </div>
  </div>
 </div>
 </body>
</html>

打开localhost:3000,会看到如下:

聊天室成功部署到服务器。

2、检测登录

在客户端和服务器之间传送消息需要用到socket.io

#安装socket.io模块
npm install --save socket.io

将server.js改动如下:

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);

app.use('/', express.static(__dirname + '/www'));

io.on('connection', function(socket){ // 用户连接时触发
 console.log('a user connected');
});

http.listen(3000, function(){
 console.log('listening on *:3000');
});

当打开localhost:3000的时候会触发服务器端io的connection事件,会在服务器打印“a user connected”,但是我们想统计一下连接该服务器的用户人数,如果有用户连接就打印“n users connected”,n为用户人数,怎么办呢?

在server.js设置一个全局数组为user,每当一个用户连接成功就在连接事件中将用户的昵称push进user,打印user.length即可知道已成功连接用户的人数。

等一等。

在用户连接的时输入昵称登录,我们应该检测一下用户的昵称是否已存在,避免昵称相同的情况发生,在服务器监听一个登录事件来判断该情况,由于一切都发生在用户连接之后,所以触发事件应该写在connection事件的回调函数中。

io.on('connection', (socket)=> {
 // 渲染在线人员
 io.emit('disUser', usersInfo);

 // 登录,检测用户名
 socket.on('login', (user)=> {
  if(users.indexOf(user.name) > -1) { // 昵称是否存在
   socket.emit('loginError'); // 触发客户端的登录失败事件
  } else {
   users.push(user.name); //储存用户的昵称
   usersInfo.push(user); // 储存用户的昵称和头像
   socket.emit('loginSuc'); // 触发客户端的登录成功事件
   socket.nickname = user.name;
   io.emit('system', { // 向所有用户广播该用户进入房间
    name: user.name,
    status: '进入'
   });
   io.emit('disUser', usersInfo); // 渲染右侧在线人员信息
   console.log(users.length + ' user connect.'); // 打印连接人数
  }
 });

system和disUser事件先不管,之后再说 区分io.emit(foo)、socket.emit(foo)、socket.broadcast.emit(foo)

io.emit(foo); //会触发所有客户端用户的foo事件
socket.emit(foo); //只触发当前客户端用户的foo事件
socket.broadcast.emit(foo); //触发除了当前客户端用户的其他用户的foo事件

接下来是客户端代码chat-client.js

$(function() {
  // io-client
  // 连接成功会触发服务器端的connection事件
  var socket = io();

  // 点击输入昵称
  $('#nameBtn').click(()=> {
   var imgN = Math.floor(Math.random()*4)+1; // 随机分配头像
   if($('#name').val().trim()!=='')
     socket.emit('login', { // 触发服务器端登录事件
      name: $('#name').val(),
      img: 'image/user' + imgN + '.jpg'
     });
   return false;
  });
  // 登录成功,隐藏登录层
  socket.on('loginSuc', ()=> {
   $('.name').hide();
  })
  socket.on('loginError', ()=> {
   alert('用户名已存在,请重新输入!');
   $('#name').val('');
  });
});

倘若登录成功,会看到如下页面:

登录检测完成。

3、系统自动提示用户状态(进入/离开)

该功能是为了实现上图所示的系统提示“XXX进入聊天室”,在登录成功时触发system事件,向所有用户广播信息,注意此时用的是io.emit而不是socket.emit,客户端代码如下

// 系统提示消息
socket.on('system', (user)=> {
 var data = new Date().toTimeString().substr(0, 8);
 $('#messages').append(`<p class='system'><span>${data}</span><br /><span>${user.name} ${user.status}了聊天室<span></p>`);
 // 滚动条总是在最底部
 $('#messages').scrollTop($('#messages')[0].scrollHeight);
});

4、显示在线用户

客户端监听一个显示在线用户的事件disUser,在以下三个时间段服务器端就触发一次该事件重新渲染一次

  1. 程序开始启动时
  2. 每当用户进入房间
  3. 每当用户离开房间
// chat-client.js
// 显示在线人员
socket.on('disUser', (usersInfo)=> {
 displayUser(usersInfo);
});
// 显示在线人员
function displayUser(users) {
 $('#users').text(''); // 每次都要重新渲染
 if(!users.length) {
  $('.contacts p').show();
 } else {
  $('.contacts p').hide();
 }
 $('#num').text(users.length);
 for(var i = 0; i < users.length; i++) {
  var $html = `<li>
   <img src="${users[i].img}">
   <span>${users[i].name}</span>
  </li>`;
  $('#users').append($html);
 }
}

5、支持发送和接收消息

用户发送消息时触发服务器端的sendMsg事件,并将消息内容作为参数,服务器端监听到sendMsg事件之后向其他所有用户广播该消息,用的socket.broadcast.emit(foo)

 // server.js
  // 发送消息事件
  socket.on('sendMsg', (data)=> {
    var img = '';
    for(var i = 0; i < usersInfo.length; i++) {
      if(usersInfo[i].name == socket.nickname) {
        img = usersInfo[i].img;
      }
    }
    socket.broadcast.emit('receiveMsg', { // 向除了发送者之外的其他用户广播
      name: socket.nickname,
      img: img,
      msg: data.msg,
      color: data.color,
      side: 'left'
    });
    socket.emit('receiveMsg', { // 向发送者发送消息,为什么分开发送?因为css样式不同
      name: socket.nickname,
      img: img,
      msg: data.msg,
      color: data.color,
      side: 'right'
    });
  });

服务器端接受到来自用户的消息后会触发客户端的receiveMsg事件,并将用户发送的消息作为参数传递,该事件会向聊天面板添加聊天内容,以下为chat-client.js代码

// 点击按钮或回车键发送消息
  $('#sub').click(sendMsg);
  $('#m').keyup((ev)=> {
   if(ev.which == 13) {
    sendMsg();
   }
  });

  // 接收消息
  socket.on('receiveMsg', (obj)=> { // 将接收到的消息渲染到面板上
   $('#messages').append(`
     <li class='${obj.side}'>
     <img src="${obj.img}">
     <div>
      <span>${obj.name}</span>
      <p>${obj.msg}</p>
     </div>
    </li>
   `);
   // 滚动条总是在最底部
   $('#messages').scrollTop($('#messages')[0].scrollHeight);
  });

  // 发送消息
  function sendMsg() {
   if($('#m').val() == '') { // 输入消息为空
    alert('请输入内容!');
    return false;
   }
   socket.emit('sendMsg', {
    msg: $('#m').val()
   });
   $('#m').val('');
   return false;
  }

6、自定义字体颜色

得益于html5的input新特性,可以通过type为color的input调用系统调色板

<!-- $('#color').val();为选中颜色,格式为#FFCCBB -->
<input type='color' id='color'> 

客户端根据用户选择的颜色渲染内容样式,代码很容易看懂,这里就不赘述了。

7、支持发送表情

发送表情其实很简单,将表情图片放在li中,当用户点击li时就将表情的src中的序号解析出来,用[emoji+表情序号]的格式存放在聊天框里,点击发送后再解析为src。就是一个解析加还原的过程,这一过程中我们的服务器代码不变,需要改变的是客户端监听的receiveMsg事件。

// chat-client.js

  // 显示表情选择面板
  $('#smile').click(()=> {
   $('.selectBox').css('display', "block");
  });
  $('#smile').dblclick((ev)=> {
   $('.selectBox').css('display', "none");
  });
  $('#m').click(()=> {
   $('.selectBox').css('display', "none");
  });

  // 用户点击发送表情
  $('.emoji li img').click((ev)=> {
    ev = ev || window.event;
    var src = ev.target.src;
    var emoji = src.replace(/\D*/g, '').substr(6, 8); // 提取序号
    var old = $('#m').val(); // 用户输入的其他内容
    $('#m').val(old+'[emoji'+emoji+']');
    $('.selectBox').css('display', "none");
  });

客户端收到之后将表情序号还原为src,更改如下

// chat-client.js

  // 接收消息
  socket.on('receiveMsg', (obj)=> {
   // 提取文字中的表情加以渲染
   var msg = obj.msg;
   var content = '';
   while(msg.indexOf('[') > -1) { // 其实更建议用正则将[]中的内容提取出来
    var start = msg.indexOf('[');
    var end = msg.indexOf(']');

    content += '<span>'+msg.substr(0, start)+'</span>';
    content += '<img src="image/emoji/emoji%20('+msg.substr(start+6, end-start-6)+').png">';
    msg = msg.substr(end+1, msg.length);
   }
   content += '<span>'+msg+'</span>';

   $('#messages').append(`
    <li class='${obj.side}'>
     <img src="${obj.img}">
     <div>
      <span>${obj.name}</span>
      <p style="color: ${obj.color};">${content}</p>
     </div>
    </li>
   `);
   // 滚动条总是在最底部
   $('#messages').scrollTop($('#messages')[0].scrollHeight);
  });

可以成功发送表情了。

8、支持发送图片

首先是图片按钮样式,发送图片的按钮是type为file的input。这里有一个改变样式的小技巧,那就是将input的透明度设为0,z-index为5,将你想要得样式放在div中,z-index设为1覆盖在input上。

<input type="file" id="file">
<i class="fa fa-picture-o" id="img"></i>
css:

.edit #file {
  width: 32.36px;
  height: 29px;
  opacity: 0;
  z-index: 5;
}
.edit #img {
  z-index: 0;
  margin-left: -43px;
}

完美

接下来是点击按钮发送图片,我们用了fileReader对象,这里有一篇不错的文章讲解了fileReader,fileReader是一个对象,可以将我们选中的文件已64位输出然后将结果存放在reader.result中,我们选中图片之后,reader.result就存放的是图片的src

// chat-client.js

  // 用户发送图片
  $('#file').change(function() {
   var file = this.files[0]; // 上传单张图片
   var reader = new FileReader();

   //文件读取出错的时候触发
   reader.onerror = function(){
     console.log('读取文件失败,请重试!');
   };
   // 读取成功后
   reader.onload = function() {
    var src = reader.result; // 读取结果
    var img = '<img class="sendImg" src="'+src+'">';
    socket.emit('sendMsg', { // 发送
     msg: img,
     color: color,
     type: 'img' // 发送类型为img
    });
   };
   reader.readAsDataURL(file); // 读取为64位
  });

由于发送的是图片,所以对页面布局难免有影响,为了页面美观客户端在接收其他用户发送的消息的时候会先判断发送的是文本还是图片,根据不同的结果展示不同布局。判断的方法是在客户发送消息的时候传入一个type,根据type的值来确实发送内容的类型。所以上面发送图片代码中触发了sendMsg事件,传入参数多了一个type属性。

响应的,我们应该在chat-client.js中修改receiveMsg事件监听函数,改为根据传入type做不同操作

chat-client.js
  // 接收消息
  socket.on('receiveMsg', (obj)=> {
   // 发送为图片
   if(obj.type == 'img') {
    $('#messages').append(`
     <li class='${obj.side}'>
      <img src="${obj.img}">
      <div>
       <span>${obj.name}</span>
       <p style="padding: 0;">${obj.msg}</p>
      </div>
     </li>
    `);
    $('#messages').scrollTop($('#messages')[0].scrollHeight);
    return;
   }

   // 提取文字中的表情加以渲染
   // 下面不变
  }); 

现在我们可以发送图片了

圆满完成一个功能齐全的聊天室!

源码地址:windlany/happy-chat,本文断断续续写了两天,真是写文章比敲代码还累...其实写一个聊天室并不难,这算是node起步作品吧。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

您可能感兴趣的文章:

  • node+express+ejs制作简单页面上手指南
  • nodejs教程 安装express及配置app.js文件的详细步骤
  • node.js Web应用框架Express入门指南
  • node+express+jade制作简单网站指南
  • NodeJS框架Express的模板视图机制分析
  • 浅析node连接数据库(express+mysql)
  • Nodejs Express4.x开发框架随手笔记
  • NodeJS Express框架中处理404页面一个方式
  • win7下安装配置node.js+express开发环境
(0)

相关推荐

  • 浅析node连接数据库(express+mysql)

    操作是在ubuntu系统的下环境,简单记录一下过程. 首先用apt-get安装数据库,键入命令 sudo apt-get install mysql-server , 一路回车,然后在一个界面设置一下数据库root的密码就好了 在数据库里面我们需要创建一些东西.键入 mysql -uroot -p××××× 来进入sql控制台. 1.先创建数据集 create database databasename : 2.use database databasename : 3.建表(这里创建一个很简单

  • nodejs教程 安装express及配置app.js文件的详细步骤

    安装express.js 如果你安装了npm,安装变得很简单,只需要在终端中运行下面的代码即可: 复制代码 代码如下: npm install express -gd -g代表安装到NODE_PATH的lib里面,而-d代表把相依性套件也一起安装.如果沒有-g的话会安装目前所在的目录(会建立一个node_modules的文件夹),你可以透过以下指令来比较两者的不同: 复制代码 代码如下: npm list -gnpm list 如果没有npm,那么我可以使用github来git下来最新的expr

  • node+express+jade制作简单网站指南

    1.建立工程文件夹:my_jade 2.下载express和jade包到本地.我个人不喜欢下载成全局的,我喜欢下到工程文件夹中去. 3.建立相关的文件夹和文件. index.js: style.css gys.jade代码: index.jade: layout.jade app.js 运行app.js:node app.js; 在浏览器中预览: 在看一个不使用页面布局的例子: 修改index.js 修改app.js 运行app.js在浏览器中预览: 单击提交 会触发ajax. .本文就先到这里

  • win7下安装配置node.js+express开发环境

    1.安装 node.js. 进入官网的下载地址:http://www.nodejs.org/download/ . 选择Windows Installer或者选择Windows Installer (.msi) 32-bit,下载安装包. 下载完成后,双击安装. 2.安装 Express. 通过nmp包管理器进行安装,安装分为: 全局安装:自动安装到"C:\Users\[当前用户]\AppData\Roaming\npm"下,并且自动将路径添加到环境变量"Path"

  • Nodejs Express4.x开发框架随手笔记

    Express: ?web application framework for?Node.js?Express 是一个简洁.灵活的 node.js Web 应用开发框架, 它提供一系列强大的特性,帮助你创建各种 Web 和移动设备应用. 目录 此文重点介绍Express4.x(具体是4.10.4)的开发框架,其中还会涉及到Mongoose,Ejs,Bootstrap等相关内容. 建立工程 目录结构 Express4.x配置文件 Ejs模板使用 Bootstrap界面框架 路由功能 Session

  • NodeJS Express框架中处理404页面一个方式

    在用 Express 的时候,路由是我最困惑的事之一.知道用 app.get('*') 可以处理所有页面,但这样除了自定义的其他路由外,静态文件是被忽略的.最近在写一个小工具的时候,找到了一个解决方案: 复制代码 代码如下: var express = require('express'),    router = require('./routes'); var app = module.exports = express.createServer(); // Configurationapp

  • node.js Web应用框架Express入门指南

    一.安装 复制代码 代码如下: $ npm install express 或者在任何地方使用可执行的 express(1) 安装: 复制代码 代码如下: \# 译注:强烈建议这种方式$ npm install -g express 二.快速上手 最快上手 express 的方法是利用可执行的 express(1) 来生成一个应用,如下所示: 创建一个 app: 复制代码 代码如下: $ npm install -g express$ express /tmp/foo && cd /tmp

  • NodeJS框架Express的模板视图机制分析

    模板引擎 Express支持许多模板引擎,常用的有: haml 的实现Haml haml.js 接替者,同时也是Express的默认模板引擎Jade 嵌入JavaScript模板EJS 基于CoffeeScript的模板引擎CoffeeKup 的NodeJS版本jQuery模板引擎 视图渲染(view randering) 视图的文件名默认需遵循"<name>.<engine>"的形式,这里<engine>是要被加载的模块的名字.比如视图layout

  • node+express+ejs制作简单页面上手指南

    1.建立工程文件夹my_ejs. 2.首先利用npm install express和npm install ejs 下载这两个家伙.至于要不要设置成全局的,看习惯,我习惯性的下载到本项目中的文件夹中my_ejs. 然后建立相应的文件: index.js: form.ejs: index.ejs app.js: 开始运行app.js node app.js,然后再浏览器端访问:localhost:1337 单击发表文章: 点击发表,跳转到首页. 好了到此为止,一个简易的"网站"算是出来

  • 零基础实现node+express个性化聊天室的示例

    本篇文章使用node+express+jquery写一个个性化聊天室,一起来get一下~(源码地址见文章末尾) 效果图 项目结构 实现功能 登录检测 系统自动提示用户状态(进入/离开) 显示在线用户 支持发送和接收消息 自定义字体颜色 支持发送表情 支持发送图片 下面将一一讲解如何实现 前期准备 node及npm环境.express.socket.io 具体实现 1.将聊天室部署到服务器 先用node搭建一个服务器,部署在localhost:3000端口,先尝试向浏览器发送一个"hello wo

  • 零基础之Node.js搭建API服务器的详解

    零基础之Node.js搭建API服务器 这篇文章写给那些Node.js零基础,但希望自己动手实现服务器API的前端开发者,尝试帮大家打开一扇门. HTTP服务器实现原理 HTTP服务器之所以能提供前端使用的API,其实现原理是服务器保持监听计算机的某个端口(通常是80),等待客户端请求,当请求到达并经过一系列处理后,服务器发送响应数据给到前端. 平时大家通过Ajax调用API,即是发起一次请求,经过服务器处理后,得到结果,然后再进行前端处理.如今使用高级编程语言,要实现服务器那部分功能已经变得非

  • ASP.NET MVC4异步聊天室的示例代码

    本文介绍了ASP.NET MVC4异步聊天室的示例代码,分享给大家,具体如下: 类图: Domain层 IChatRoom.cs using System; using System.Collections.Generic; namespace MvcAsyncChat.Domain { public interface IChatRoom { void AddMessage(string message); void AddParticipant(string name); void GetM

  • Python基于Socket实现简易多人聊天室的示例代码

    前言 套接字(Sockets)是双向通信信道的端点. 套接字可以在一个进程内,在同一机器上的进程之间,或者在不同主机的进程之间进行通信,主机可以是任何一台有连接互联网的机器. 套接字可以通过多种不同的通道类型实现:Unix域套接字,TCP,UDP等. 套接字库提供了处理公共传输的特定类,以及一个用于处理其余部分的通用接口. socket模块: 要创建套接字,必须使用套接字模块中的socket.socket()函数,该函数具有一般语法 s = socket.socket (socket_famil

  • Python实现网络聊天室的示例代码(支持多人聊天与私聊)

    实验名称: 网络聊天室 功能: i. 掌握利用Socket进行编程的技术 ii. 掌握多线程技术,保证双方可以同时发送 iii. 建立聊天工具 iv. 可以和单人聊天 v. 可以和多个人同时进行聊天 vi. 使用图形界面,显示双方的语录 vii. 程序可以在一定程度上进行错误识别 概述 实验通过聊天室可以完成单人或多人之间的聊天通信,功能的实现主要是通过Socket通信来实现.本次实验采用客户端/服务器(C/S)架构模式,通过Python语言来编写服务器端与客户端的程序.运用多线程可完成多点对多

  • Java实现NIO聊天室的示例代码(群聊+私聊)

    功能介绍 功能:群聊+私发+上线提醒+下线提醒+查询在线用户 文件 Utils 需要用maven导入下面两个包 <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.18</version> </dependency> <dependency> <group

  • Qt实现网络聊天室的示例代码

    目录 1. 效果演示 2. 预备知识 2.1 QTcpServer 2.2 QTcpServer信号 2.3 QTcpSocket 2.4 QTcpSocket信号 3. 通信流程 3.1 服务器端 3.2 客户端 1. 效果演示 客户端 服务器 连接成功之后 2. 预备知识 在Qt中,实现网络编程的方式比用C++或C实现要方便简单许多,因为Qt已经替我们封装好了,我们会使用就可以了,然后大家还需要了解Qt 的信号槽机制,可以参考我这篇文章,Qt信号槽 2.1 QTcpServer QTcpSe

  • 利用Python打造一个多人聊天室的示例详解

    一.实验名称 建立聊天工具 二.实验目的 掌握Socket编程中流套接字的技术,实现多台电脑之间的聊天. 三.实验内容和要求 vii.掌握利用Socket进行编程的技术 viii.必须掌握多线程技术,保证双方可以同时发送 ix.建立聊天工具 x.可以和多个人同时进行聊天 xi.必须使用图形界面,显示双方的语录 四.实验环境 PC多台,操作系统Win7,win10(32位.64位) 具备软件python3.6 . 五.操作方法与实验步骤 服务端 1.调入多线程.与scoket包,用于实现多线程连接

  • SpringBoot+Netty实现简单聊天室的示例代码

    目录 一.实现 1.User类 2.SocketSession类 3.SessionGroup 4.WebSocketTextHandler类 5.WebSocketServer类 6.index.html 二.效果 一.实现 1.User类 import java.util.Objects; public class User {     public String id;     public String nickname;     public User(String id, Strin

  • 零基础搭建Node.js、Express、Ejs、Mongodb服务器及应用开发入门

    本文改自非鱼的<[翻译]前端开发人员入门指南,从零开始搭建Node.js, Express, Jade, Mongodb服务器>,之所以把Jade换成Ejs,是因为我觉得ejs更符合WEB编程人员的习惯,更确切说应该是更符合PHP.ASP程序员的使用习惯.好了,废话不多说,直接开始教程. 第1部分 – 15分钟安装 如果你真的是从零开始学,那就花点时间先把环境搭建起来吧.这不难,我用的是Win8,所以这看上去跟那些用Mac和Ubuntu或者其它*nix系统的教程有点区别,不过大致是一样的. 第

随机推荐