nodejs 聊天室

首先確保本地環(huán)境已經安裝了 node 環(huán)境
建立項目文件夾,我的是 node,以下操作都是在 node 文件夾下面操作的
然后安裝 express 框架

npm install --save express@4.15.2

安裝 socket.io 模塊

npm install --save socket.io

我的 demo 也是安裝手冊上來的,

注意要點

在 vue 中的 created(){} 里面的變量,你在 data 里初始值是什么,這個變量的值就永遠是什么,這個個坑跟 vue 的生命周期有關。所有在做一對一聊天,房間聊天的處理中,監(jiān)聽聊天通道的時候需要注意聊天對象的ID號和房間號的選擇,其實你可以把這個監(jiān)聽放在選擇聊天對象或者房間的點擊事件中

  • index.js
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var config = require('config'); // 學習模塊的引入

app.get('/', function (req, res) {
    // res.send('<h1>Hello World</h1>');
    res.sendFile(__dirname + '/index.html');
});


// 監(jiān)聽連接處理
io.on('connection', socket => {
    // socket.on('chat message', function (msg) {
    //     console.log('message:' + msg);
    // });
    //
    socket.on('disconnect', function () {
        console.log('user disconnected');
    })

    // 連接后,監(jiān)聽 chat message 通道
    socket.on('chat message', msg => {
        // 這個 msg 是熊 index.html 中發(fā)送過來的   io().emit('chat message', $('#m').val());
        // io.emit 是往某個通道發(fā)送信息,第一個參數是通道,第二個參數是信息 這個與 socket.on 監(jiān)聽的通道可以不一致
        io.emit('send message', msg);
    });

})

http.listen(config['socket_port'], function () {
    console.log('listening on *:3000');
})
  • inde.html
<!doctype html>
<html>
<head>
    <title>Socket.IO chat</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font: 13px Helvetica, Arial;
        }

        form {
            background: #000;
            padding: 3px;
            position: fixed;
            bottom: 0;
            width: 100%;
        }

        form input {
            border: 0;
            padding: 10px;
            width: 90%;
            margin-right: .5%;
        }

        form button {
            width: 9%;
            background: rgb(130, 224, 255);
            border: none;
            padding: 10px;
        }

        #messages {
            list-style-type: none;
            margin: 0;
            padding: 0;
        }

        #messages li {
            padding: 5px 10px;
        }

        #messages li:nth-child(odd) {
            background: #eee;
        }
    </style>
    <!--<script src="/socket.io/socket.io.js"></script>-->
    <script src="/socket.io/socket.io.js"></script>
    <script src="https://code.jquery.com/jquery-1.11.1.js"></script>
    <script>
        $(function () {
            var socket = io();
            $('form').submit(function (e) {
                e.preventDefault(); // prevents page reloading
                // 向某個通道發(fā)送信息
                socket.emit('chat message', $('#m').val());
                $('#m').val('');
                return false;
            });
            // 監(jiān)聽 chat message 通道
            socket.on('send message', msg => {
                $('#messages').append($('<li>').text(msg));
                // 上下滑動屏幕
                window.scrollTo(0, document.body.scrollHeight);
            });
        });
    </script>
</head>
<body>
<ul id="messages"></ul>
<form action="">
    <input id="m" autocomplete="off"/>
    <button>Send</button>
</form>

</body>
</html>
  • configs.js
module.exports = {
   'socket_port': '3000',
}

程序講解

首先你需要對 nodejs 語法要有基本的了解,如果不了解,我建議看 菜鳥手冊
然后我們要知道,nodejs 是基于事件驅動的語法,也就是有事件,才會有相應的觸發(fā)。
事件可以理解為事件就是客戶點擊了某個url,觸發(fā)就是我們對某個路由的控制器做的相應處理
此處的觸發(fā),就比如 io.on('connection',function(socket){}), 此處的 on() 就相當于是監(jiān)聽 connection 是固定的參數,監(jiān)聽到有客戶端連接的意思,
on 的第二個參數就是連接后做的處理,相當于是控制器

程序執(zhí)行流程講解

index.js 中首 io模塊 先監(jiān)聽了 connection連接 的處理,連接后監(jiān)聽了 'chat message'消息通道
index.html 中,往 chat message 通道發(fā)送信息 socket.emit('chat message', $('#m').val());
這個時候 index.js 中的 socket.on('chat message', msg => {}) 監(jiān)聽到有消息發(fā)送過來,這里的 msg 就是 index.html 中發(fā)送的消息。
收到消息后,我們需要把消息發(fā)送到某個通道,此處的通道名字我用的是 sen message ,io.emit('send message', msg); ,我把這個消息發(fā)送到 send message 通道
我們在 index.html 前端頁面監(jiān)聽了 send message 通道 socket.on('send message',msg=>{}),然后對監(jiān)聽的數據做處理即可

以上情況,我們是針對群聊處理的。也就是每個人都是監(jiān)聽的 send message 通道,發(fā)送信息都是發(fā)送到了 chat message 通道,如果需要私聊,或者指定房間,需要更改這兩個參數即可


一對一聊天

  • index.html
<body>
<h1>請選擇聊天的對象</h1>
<select name="username" id="choose">
    <option value="">null</option>
    <option value="test1">test1</option>
    <option value="test2">test2</option>
    <option value="test3">test3</option>
    <option value="test4">test4</option>
    <option value="test5">test5</option>
</select>
<button id="b_click">ok</button>

<ul id="messages"></ul>
<form action="">
    <input id="m" autocomplete="off"/>
    <button>Send</button>
</form>
<script>
    var to = '';
    $('#b_click').click(function () {
        to = $('#choose').val();
    });
    var username = prompt('請輸入你的名字', '');
    // 聊天對象
    if (to == '') {
        to = username;
    }

    $(function () {
        var socket = io();
        $('form').submit(function (e) {
            e.preventDefault(); // prevents page reloading
            // 向某個通道發(fā)送信息
            var data = $('#m').val();
            var msg = {username: username, to: to, data: data};
            socket.emit('chat message', msg);
            $('#m').val('');
            return false;
        });
        // 監(jiān)聽 chat message 通道
        socket.on(to, msg => {
            // 如果 發(fā)送者和接收者都是自己,表示還沒有開啟對話,將對話對象更細昵稱 msg.username
            if (username == to) {
                to = msg.username;
            }
            $('#messages').append($('<li>').text(msg.data));
            // 上下滑動屏幕
            window.scrollTo(0, document.body.scrollHeight);
        });

    });
</script>
</body>
  • index.js
同上面的 index.js 此處只展示改變代碼的部分
...
// 監(jiān)聽連接處理
io.on('connection', socket => {
    // 連接后,監(jiān)聽 chat message 通道
    socket.on('chat message', msg => {
        io.emit(msg.to, msg);
    });

})
...
  • 思路分析
    我們在 index.html 頁面中監(jiān)聽的信息通道都是to 參數的值,這個通道在 demo 中,其實就是test
    long 主動跟 test 聊天,在 long 的頁面中 username=long to =test
    在 test 頁面中 username 和 to 的值都是 test 所以兩人都是監(jiān)聽的 test 通道,都可以接收到信息

  • 不適用 express 框架也可以的

var fs = require('fs');
var app = require('http').createServer(function (req, res) {
    fs.readFile(__dirname + '/index.html', function (err, data) {
        if (err) {
            res.writeHead(500);
            return res.end('Error loading index.html');
        }
        res.writeHead(200);
        res.end(data);
    })
})
io = require('socket.io')(app);
// 監(jiān)聽連接處理
io.on('connection', socket => {
    socket.on('disconnect', function () {
        console.log('user disconnected');
    })

    // 連接后,監(jiān)聽 chat message 通道
    socket.on('chat message', msg => {
        io.emit(msg.to, msg);
        // 如果發(fā)送人和接收人都是同一個人,則不需要重復發(fā)送給自己
        if (msg.to != msg.username) {
            io.emit(msg.username, msg);
        }
    });

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

某人上線下線的提醒

  • index.html
    var username = prompt('請輸入你的名字', '');
    var socket = io();
    socket.emit('coming', username);  // 在輸入名字之后,將新用戶推送到 coming 通道
  • index.js
// 監(jiān)聽連接處理
io.on('connection', socket => {
    // 連接后,監(jiān)聽 chat message 通道
    socket.on('coming', msg => {
        socket.name = msg; // 這個通道有消息過來的時候,將他賦值給 socket 的一個屬性
,因為 disconnect 與這個不在這個作用域,所以要放在 socket 的屬性上
        console.log(msg + '上線了');
    });

    socket.on('disconnect', function () {
     // 這里可以寫自己的邏輯業(yè)務,比如通知某個房間的人
        console.log(socket.name + '離開了');
    })
})

vue 實現一對一聊天

首先后端的服務還是使用上面的 index.js 去處理
在前端

  • vue/index.html 中引入 socket.io.js 文件
 <div id="app"></div>
    <script src="http://localhost:3000/socket.io/socket.io.js"></script>
    <script type="text/javascript">
      const socket = io.connect('http://localhost:3000');
    </script>
先引入后端的 socket.io.js 文件,就可以獲取 io 這個對象。我們預定義 socket 變量方便程序中使用
  • vue/src/router/index.js 定義聊天路由
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import Chat from '@/components/Chat'
import ChatList from '@/components/ChatList'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'HelloWorld',
      component: HelloWorld
    },{
      path: '/chat',
      name: 'Chat',
      component: Chat
    },{
      path: '/chatlist',
      name: 'ChatList',
      component: ChatList
    }
  ]
})
  • vue/src/components/ChatList.vue 選擇聊天對象列表,這步不重要
<template>
    <!--  用戶列表 -->
    <div>
        <h2>聊天對象用戶列表</h2>
        <ul>
            <li v-for="(username,index) in usernameList">
                <!--<router-link to="/chat">-->
                    <button @click="$router.push({path:'/chat',query: {username,index}})">{{ username }}</button>
                <!--</router-link>-->

            </li>
        </ul>
    </div>
</template>

<script>
    export default {
        data() {
            return {
                usernameList: [
                    'test1',
                    'test2',
                    'test3',
                    'test4',
                    'test5',
                ],
            }
        }
    }
</script>
  • vue/src/components/Chat.vue 聊天頁面
<template>
    <div>
        <ul id="messages">
            <li v-for="msg in msgList" :class="[msg.username === username ?'right':'left']">{{
                msg.username+':'+msg.content }}
            </li>
        </ul>
        <form action="">
            <input id="m" autocomplete="off" v-model="content">
            <button @click="sendMessage">{{ sendInfo }}</button>
        </form>
    </div>
</template>

<script>
    export default {
        data() {
            return {
                content: '',
                sendInfo: "發(fā)送",
                msgList: [],
                username: '',
                chatTo: '',
                left: false,
                right: false,
            }
        },
        methods: {
            sendMessage: function (e) {
                e.preventDefault();
                var msg = {username: this.username, chatTo: this.chatTo, content: this.content}
                socket.emit('one to one message', msg);
                this.content = '';
            }
        },
        created() {
            this.username = prompt('請輸入你的名字');
            var query = this.$route.query;
            if (Object.keys(query).length === 0) {
                this.chatTo = this.username;
                // alert('請選擇聊天對象');
            } else {
                this.chatTo = query.username;
            }
            // 監(jiān)聽
            socket.on(this.chatTo, msg => {
                this.msgList.push({
                    username: msg.username,
                    chatTo: msg.chatTo,
                    content: msg.content,
                });
                // 上下滑動屏幕
                window.scrollTo(0, document.body.scrollHeight);

            });
        },
    }
</script>
<style>
    form {
        background: #000;
        padding: 3px;
        position: fixed;
        bottom: 0;
        width: 100%;
    }

    form input {
        border: 0;
        padding: 10px;
        width: 70%;
        margin-right: .5%;
    }

    form button {
        width: 20%;
        background: rgb(130, 224, 255);
        border: none;
        padding: 10px;
    }

    #messages {
        list-style-type: none;
    }

    #messages li {
        padding: 5px 10px;
        width: 50%;
    }

    #messages li:nth-child(odd) {
        background: #eee;
    }

    .left {
        float: left;
    }

    .right {
        float: right;
    }
</style>
image.png

多對多聊天(房間聊天,群聊)

  • 后端 index.js
....
// 監(jiān)聽連接處理
io.on('connection', socket => {
    // 私聊通道監(jiān)聽
    socket.on('one to one message', msg => {
        // 發(fā)送給私聊對象
        io.emit(msg.chatTo, msg);
    });

    // f房間聊天室監(jiān)聽
    socket.on('chat room message', msg => {
        // 發(fā)送給某個房間
        io.emit('chat room receive' + msg.roomNum, msg)
    });
})
....
  • ChatRoom.vue
<template>
    <div>
        <ChooseRoom v-bind:roomList="roomList" v-if="!roomNum" v-on:chooseRoom="chooseRoom"></ChooseRoom>
        <h1>進入聊天室</h1>
        <ul id="messages">
            <li v-for="msg in msgList" :class="[msg.username === username ?'right':'left']">{{
                msg.username+':'+msg.content }}
            </li>
        </ul>
        <form action="">
            <input id="m" autocomplete="off" v-model="content">
            <button @click="sendMessage">{{ sendInfo }}</button>
        </form>
    </div>
</template>
<script>
    import ChooseRoom from './ChooseRoom'
    export default {
        data() {
            return {
                content: '',
                sendInfo: "發(fā)送",
                msgList: [],
                username: '',
                roomNum: '',
                left: false,
                right: false,
                roomList: [
                    {id: '1', name: '1號房間'},
                    {id: '2', name: '2號房間'},
                    {id: '3', name: '3號房間'},
                    {id: '4', name: '4號房間'},
                    {id: '5', name: '5號房間'},
                ],
            }
        },
        components: {
            ChooseRoom
        },

        methods: {
            // 發(fā)送信息
            sendMessage: function (e) {
                e.preventDefault();
                var msg = {username: this.username, roomNum: this.roomNum, content: this.content}
                socket.emit('chat room message', msg);
                this.content = '';
            },
            chooseRoom: function (id) {
                this.roomNum = id;
                socket.on('chat room receive'+this.roomNum, msg => {
                    this.msgList.push({
                        username: msg.username,
                        content: msg.content,
                    });
                    // 上下滑動屏幕
                    window.scrollTo(0, document.body.scrollHeight);
                });
            }
        },
        created() {
            this.username = prompt('請輸入你的名字');
        },
    }
</script>
  • ChooseRoom.vue
<template>
    <div>
        <h1>選擇房間</h1>
        <ul>
            <li v-for="room in roomList">
                <button @click="$emit('chooseRoom',room.id)">{{ room.name }}</button>
            </li>
        </ul>
    </div>
</template>
<script>
    export default {
        props: ['roomList'],
    }
</script>

在一個小圖表上顯示有多少條未讀數據的做法是,直接監(jiān)聽相關的端口,j每次有消息通知的時候將一個變量加1即可

data() {
    return {
        msgCount: 0
    }
},

created() {
    // socket.ChatList = [];
    // 一對一聊天
    socket.on(this.username, msg => {
        this.msgCount++;
        // socket.ChatList.push({
        //     username: msg.username,
        //     chatTo: msg.chatTo,
        //     content: msg.content,
        // });
    });
}

如果想點擊小圖標后顯示聊天的內容,可以在上面的處理中將接受的數據賦值給 socket 的一個自定義變量,這樣的話,跨頁面也是可以獲取到這個變量的

一對一聊天,顯示聊天對象列表和內容

  • 思路,聊天用戶發(fā)送信息的時候,在后端使用 redis 的 rpush 保存數據,并將聊天人使用 sadd 存入 set ,其實也可以使用 hash 的 hincryby 每次將聊天記錄加1 ,但是我看 nodejs 的 redis 沒有這個操作指令。
    對了,用戶一對一的通道名子,我根據兩人的名字比較,大的值在前面。js 語法也是可以直接比較字符串的,這樣就可以統(tǒng)一通道規(guī)則

  • 前端首頁 index.vue

<template>
    <div class="hello">
        <!--<button @click="toChat($router,username,chatTo)">-->
        <!--<h1>未查看信息條數{{ msgCount }}</h1>-->
        <!--</button>-->
        <h1>聊天列表</h1>
        <ul>
            <li v-for="(chatName,index) in chatList" :key="index">

                <button @click="toChat($router,username,chatName)">
                    <h1>{{ chatName }}</h1>
                </button>
            </li>
        </ul>
    </div>
</template>

<script>
    import originJsonp from '../jsonp';

    export default {
        name: 'HelloWorld',
        data() {
            return {
                msgCount: 0,
                username: '',
                chatTo: '',
                chatList: [], // 聊天人列表
            }
        },
        methods: {
            toChat: function ($router, username, chatTo) {
                let chatSocket = username > chatTo ? username + '-' + chatTo : chatTo + '-' + username;
// 也可以 let arr = [username,chatTo];
//  let chatSocket =  arr.sort().join('_');
                $router.push({path: '/chat', query: {username, chatTo, chatSocket}})
            }
        },
        created() {
            var vm = this;
            if (this.username === '') {
                this.username = this.chatTo = prompt('請輸入你的名字');
            }
            // 登陸后,獲取此用戶通道的未讀信息
            originJsonp({
                "method": 'get chat list',
                "username": vm.username,
            }).then(function (response) {
                console.log(response);
                vm.chatList = response
            })

            // 一對一聊天
            socket.on(this.username, msg => {
                this.msgCount++;
            });
        }
    }
</script>
  • 前端聊天頁面 chat.vue
<template>
    <div>
        <h1>私聊</h1>
        <ul id="messages">
            <li v-for="msg in msgList" :class="[msg.username === username ?'right':'left']">
                {{ msg.username+':'+msg.content }}
            </li>
        </ul>
        <form action="">
            <input id="m" autocomplete="off" v-model="content">
            <button @click="sendMessage">{{ sendInfo }}</button>
        </form>
    </div>
</template>

<script>
    import originJsonp from '../jsonp';

    export default {
        props: ['chatList'],
        data() {
            return {
                content: '',
                sendInfo: "發(fā)送",
                msgList: [],
                username: '',
                chatTo: '',
                left: false,
                right: false,
                chatSocket: '', // 兩人的聊天通道
            }
        },
        methods: {
            sendMessage: function (e) {
                e.preventDefault();
                var msg = {
                    username: this.username,
                    chatTo: this.chatTo,
                    content: this.content,
                    chatSocket: this.chatSocket
                }
                socket.emit('one to one message', msg);
                this.content = '';
            }
        },
        created() {
            var vm = this;
            var query = this.$route.query;
            if (Object.keys(query).length === 0) {
                this.username = prompt('請輸入你的名字');
                // 如果直接進來的  用戶和聊天對象都是自己
                this.chatTo = this.username;
            } else {
                // 否則是從 chatList 頁面進來的
                this.chatTo = query.chatTo;
                if (this.username === '' && !query.username) {
                    //  從 ChatList 頁面進來的參數有 ?chatTo=test1&index=0
                    this.username = prompt('請輸入你的名字');
                } else {
                    // 從首頁進來的參數有 ?username=test1&chatTo=test1
                    this.username = query.username;
                    // todo ajax 請求redis 接口 賦值給 this.msgList
                    this.chatSocket = vm.username > vm.chatTo ? vm.username + '-' + vm.chatTo : vm.chatTo + '-' + vm.username;
                }
            }
            if (!this.chatSocket) {
                // 兩人的聊天通道  從大到校排序
                this.chatSocket = vm.username > vm.chatTo ? vm.username + '-' + vm.chatTo : vm.chatTo + '-' + vm.username;
            }
            originJsonp({
                "method": "one to one message",
                "username": vm.username,
                "chatSocket": this.chatSocket,
            })
                .then(function (response) {
                    response.forEach(function (value, index) {
                        // 原來存的是json 字符串  需要轉換成對象
                        response[index] = JSON.parse(value);
                    })
                    vm.msgList = response
                })
                .catch(function (error) {
                    console.log(error);
                });
            // 一對一聊天
            socket.on(this.chatSocket, msg => {
                this.msgList.push({
                    username: msg.username,
                    chatTo: msg.chatTo,
                    content: msg.content,
                });
                // 上下滑動屏幕
                window.scrollTo(0, document.body.scrollHeight);
            });
        },
    }
</script>
<style>
    form {
        background: #000;
        padding: 3px;
        position: fixed;
        bottom: 0;
        width: 100%;
    }

    form input {
        border: 0;
        padding: 10px;
        width: 70%;
        margin-right: .5%;
    }

    form button {
        width: 20%;
        background: rgb(130, 224, 255);
        border: none;
        padding: 10px;
    }

    #messages {
        list-style-type: none;
    }

    #messages li {
        padding: 5px 10px;
        width: 50%;
    }

    #messages li:nth-child(odd) {
        background: #eee;
    }

    .left {
        float: left;
    }

    .right {
        float: right;
    }
</style>

  • 后端 index.js
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);

var redis = require('redis');
var client = redis.createClient(6379, '127.0.0.1');
const ONE_TO_ONE = 'one to one message'; // 一對一聊天
const ROOM_CHAT = 'chat room receive'; // 房間聊天
const SET_CHAT_LIST = 'chat list'; // 聊天對象列表

app.get('/', function (req, res) {
    res.sendFile(__dirname + '/index.html');
});

// 監(jiān)聽連接處理
io.on('connection', socket => {
    // 私聊通道監(jiān)聽
    socket.on(ONE_TO_ONE, msg => {
        console.log(msg.chatSocket);
        // 發(fā)送給私聊對象
        io.emit(msg.chatSocket, msg);
        // 將聊天語句存入 redis
        client.rpush(ONE_TO_ONE + msg.chatSocket, JSON.stringify(msg), function (err, data) {
            console.log(data)
        })
        // 將聊天人發(fā)送給聊天對象的 set 集合中
        client.sadd(SET_CHAT_LIST + msg.chatTo, msg.username, function (err, data) {
            console.log(data)
        });

    });

    // f房間聊天室監(jiān)聽
    socket.on('chat room message', msg => {
        // 發(fā)送給某個房間
        io.emit(ROOM_CHAT + msg.roomNum, msg)
        // 將聊天語句存入 redis
        client.rpush(ROOM_CHAT + msg.roomNum, JSON.stringify(msg), function (err, data) {
            console.log(data)
        })
    });

})

http.listen(3000, function () {
    console.log('listening on *:3000');
})
  • 后端PHP 接口 redis.php
<?php

header('Access-Control-Allow-Origin:*'); // 單個域名處理
define('SET_CHAT_LIST', 'chat list'); // 聊天列表

//連接本地的 Redis 服務
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
//查看服務是否運行

if (!isset($_GET['method'])) {
    echo $_GET['callback'] . "(請傳入請求參數)";
}

$username = isset($_GET['username']) ? $_GET['username'] : ''; // 用戶名
$method = isset($_GET['method']) ? $_GET['method'] : ''; // 請求方法
$chatSocket = isset($_GET['chatSocket']) ? $_GET['chatSocket'] : ''; // 請求方法
$chatTo = isset($_GET['chatTo']) ? $_GET['chatTo'] : ''; // 請求方法

$arr = [];
switch ($method) {
    case 'one to one message': // 一對一聊天
        $arr = $redis->lRange($method . $chatSocket, 0, -1);
        break;
    case 'set chat list': //
        $chatTo = $_GET['chatTo'];
        $arr = $redis->hIncrBy($method . $username, $chatTo, HASH_INC_BY);
        break;
    case 'get chat list': // 獲取聊天列表
        $arr = $redis->sMembers(SET_CHAT_LIST . $username);
        break;

}

$result = json_encode($arr);
$callback = $_GET['callback'];
echo $callback . "($result)";
  • 我這里設計的是只要發(fā)送信息,node 后端就直接使用 redis 的 sadd 存入集合,但是這樣可能沒必要,因為只需要存入一次就可以了,改善方式,可以是在進入本聊天頁面的時候,直接請求一個 php 接口,將聊天用戶存入 sadd 。但是這樣就是還沒有聊天就存入了聊天對象,好像也不合適


    image.png

    image.png

    image.png
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • https://nodejs.org/api/documentation.html 工具模塊 Assert 測試 ...
    KeKeMars閱讀 6,603評論 0 6
  • 英文文檔,一開始我也是抗拒的,邊翻譯邊看,也就花費了1個小時基本就閱讀過了,我的英文基礎其實很差。附上鏈接:鏈接:...
    lonecolonel閱讀 10,411評論 3 1
  • 網絡編程 一.楔子 你現在已經學會了寫python代碼,假如你寫了兩個python文件a.py和b.py,分別去運...
    go以恒閱讀 2,246評論 0 6
  • Cover 效果圖 老樣子,還是先放個效果圖,動態(tài)圖,有點大(4M)請耐心等加載。 隨便說說 最近在做東西的時候有...
    iimT閱讀 15,364評論 3 25
  • 股東是公司的堅強動力,沒有股東的支持和認可,公司的日子也會有點麻煩。 一個問題:作為股東,你知道自己每股收益嘛? ...
    高墻冥思_5a44閱讀 676評論 0 1

友情鏈接更多精彩內容