图片上传功能中,预览功能实现
    方法一:FileReader
    方法二:createObjectURL

    1. const file = document.querySelector('#file')
    2. const img = document.querySelector('#img')
    3. 方法一:
    4. file.onchange = () => {
    5. // 浏览器中的 fs,但是只能操作用户选择的文件
    6. const reader = new FileReader()
    7. // 第二步:
    8. // 当图片读取转换完成,会触发 load 事件
    9. reader.addEventListener("load", function () {
    10. console.log(reader.result)
    11. // 此处得到的是一个 base64 编码之后的内容
    12. // 你可以认为图片文件文本化了
    13. img.src = reader.result
    14. }, false)
    15. // 第一步:
    16. // 开始读文件
    17. reader.readAsDataURL(file.files[0])
    18. }
    19. // 方法二:
    20. // file.onchange = () => {
    21. // // 使用
    22. // const data = URL.createObjectURL(file.files[0])
    23. // img.src = data
    24. // // 最好在使用完毕 data 之后,把它释放掉
    25. // // URL.revokeObjectURL(data)
    26. // }

    HTTP缓存

    缓存说的是GET请求

    • 用node中原生的http模块来创建http服务进行测试
    • 观察请求的打印日志

    console.log

    • Axios 中的错误对象继承自 JavaScript 中的 Error 对象
    • console.log 内容和数据类型无关
    • 浏览器输出Error对象时候会读取它内部的 stack 属性
    • 所以打印的error只能看到文字,但是在代码中能点出方法
    • MDN中的描述:通过Error的构造器可以创建一个错误对象。请注意,这是一个对像!

    socket.io

    • 浏览器服务端都要用到此插件,同时使用才能进行通信
    • socket使用socket协议,http使用http协议,完全不同
    • socket可是实现群发和单发功能
    • 使用socket能很快速实现一个聊天功能,并不复杂。

    简单实现

    1. <!doctype html>
    2. <html>
    3. <head>
    4. <title>Socket.IO chat</title>
    5. <style>
    6. * { margin: 0; padding: 0; box-sizing: border-box; }
    7. body { font: 13px Helvetica, Arial; }
    8. form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
    9. form input { border: 0; padding: 10px; width: 90%; margin-right: 0.5%; }
    10. form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
    11. #messages { list-style-type: none; margin: 0; padding: 0; }
    12. #messages li { padding: 5px 10px; }
    13. #messages li:nth-child(odd) { background: #eee; }
    14. </style>
    15. </head>
    16. <body>
    17. <div id="app">
    18. <form action="">
    19. <input v-model="nickname" type="text">
    20. <button @click.prevent="handleNickname"></button>
    21. </form>
    22. <!-- 消息列表 -->
    23. <ul id="messages">
    24. <li
    25. v-for="(item, index) in messageList"
    26. :key="index"
    27. >
    28. {{ item }}
    29. </li>
    30. </ul>
    31. <!-- 发送消息的表单 -->
    32. <form action="">
    33. <div style="border: 1px solid #000;">
    34. <input v-model="nickname" type="text">
    35. <button @click.prevent="handleNickname">昵称</button>
    36. </div>
    37. <!-- 广播 -->
    38. <input
    39. v-model="message"
    40. autocomplete="off"
    41. />
    42. <button
    43. @click.prevent="handleSend"
    44. >广播</button>
    45. <!-- 私聊 -->
    46. <div style="border: 1px solid #000;">
    47. <input v-model="privateMessage" type="text">
    48. <input v-model="privateUser" type="text">
    49. <button @click.prevent="handlePrivateMessage">私聊</button>
    50. </div>
    51. </form>
    52. </div>
    53. <!-- 加载 socket.io 客户端 -->
    54. <script src="/socket.io/socket.io.js"></script>
    55. <script src="https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.min.js"></script>
    56. <script>
    57. // WebSocket 通过 HTTP 协议建立连接
    58. // 建立连接成功后使用 WebSocket 进行通信
    59. const socket = io()
    60. // 接收服务端消息
    61. // socket.on('hello', data => {
    62. // console.log(data)
    63. // })
    64. socket.on('connect', () => {
    65. })
    66. const app = new Vue({
    67. el: '#app',
    68. data: {
    69. message: '',
    70. messageList: [], // 消息列表
    71. nickname: '',
    72. privateMessage: '',
    73. privateUser: ''
    74. },
    75. created () {
    76. socket.on('message', data => {
    77. // console.log('message => ', data)
    78. this.messageList.push(`${data.nickname}说:${data.message}`)
    79. })
    80. socket.on('chat-count', count => {
    81. this.messageList.push(`当前在线人数:${count}`)
    82. })
    83. socket.on('private-message', data => {
    84. console.log('private-message', data)
    85. this.messageList.push(`${data.nickname} 对你说:${data.message}`)
    86. })
    87. },
    88. methods: {
    89. // 发送消息
    90. handleSend () {
    91. socket.emit('message', this.message)
    92. },
    93. handleNickname () {
    94. socket.emit('nickname', this.nickname)
    95. },
    96. handlePrivateMessage () {
    97. socket.emit('private-message', {
    98. privateUser: this.privateUser,
    99. privateMessage: this.privateMessage
    100. })
    101. }
    102. }
    103. })
    104. </script>
    105. </body>
    106. </html>
    1. // 后台
    2. const express = require('express')
    3. const http = require('http')
    4. const app = express()
    5. // 存储所有的客户端连接 socket
    6. const clients = []
    7. // 创建服务实例
    8. const server = http.createServer(app)
    9. // 在 HTTP 服务中集成 socket.io 用来提供 WebSocket 服务
    10. const io = require('socket.io')(server)
    11. // 通过 app 设置的都是 HTTP 资源请求处理
    12. // 托管 public 目录中的静态资源
    13. app.use(express.static('./public'))
    14. // 通过 io 设置的都是 WebSocket 资源请求处理
    15. io.on('connection', (socket) => {
    16. // clients.push(socket)
    17. console.log('a user connected')
    18. // 当客户端断开连接后触发该事件
    19. // socket.on('disconnect', () => {
    20. // console.log('user disconnected')
    21. // const index = clients.findIndex(c => c.socket === socket)
    22. // if (index !== -1) {
    23. // clients.splice(index, 1)
    24. // }
    25. // })
    26. socket.on('nickname', nickname => {
    27. console.log(nickname)
    28. clients.push({
    29. // 名字: 连接信息
    30. nickname,
    31. socket
    32. })
    33. socket.emit('nickname', '注册成功')
    34. })
    35. socket.emit('chat-count', clients.length)
    36. socket.on('message', data => {
    37. const client = clients.find(c => c.socket === socket)
    38. // console.log(data)
    39. // 广播给所有的聊天室客户端
    40. io.emit('message', {
    41. isPrivate: false,
    42. nickname: client.nickname,
    43. message: data
    44. })
    45. })
    46. socket.on('private-message', data => {
    47. console.log('private-message', data)
    48. // 找到私聊用户,给它发送消息
    49. const privateUser = clients.find(c => c.nickname === data.privateUser)
    50. if (privateUser) {
    51. console.log(privateUser)
    52. privateUser.socket.emit('private-message', {
    53. nickname: clients.find(c => c.socket === socket).nickname,
    54. message: data.privateMessage
    55. })
    56. }
    57. })
    58. })
    59. server.listen(3000, () => {
    60. console.log(`Server is running at http://localhost:3000`)
    61. })

    后台管理项目总结:

    • 用await 的实现方式让代码看起来可阅读性更好了
    • loading 的关闭只用写一次了
    • el-upload 中上传限制部分代码 ```javascript beforeAvatarUpload (file: any) {

      1. const isJPG = file.type === 'image/jpeg'
      2. const isLt2M = file.size / 1024 / 1024 < this.limit
      3. if (!isJPG) {
      4. this.$message.error('上传头像图片只能是 JPG 格式!')
      5. }
      6. if (!isLt2M) {
      7. this.$message.error(`上传头像图片大小不能超过 ${this.limit}MB!`)
      8. }
      9. return isJPG && isLt2M

      },

    ```

    • 阿里云上传
      • 没什么难点,就是根据文档,进行API编写和调用
      • 而且这个接口是后端实现的,前端需要按照后端的规则进行调用
      • new FormData()
        • FormData 接口提供了一种表示表单数据的键值对 key/value 的构造方式,并且可以轻松的将数据通过XMLHttpRequest.send() 方法发送出去。 —— MDN
    • (this.$refs[‘menu-tree’] as Tree) 这中写法
    • 在async 中请求没有先后顺序的数据
      • const ret = await Promise.all([getAllResources(), getResourceCategories()])