Aplicativo de mensagens instantâneas, incluindo servidor, gerenciamento e cliente
Agora implantado e online, bem-vindo para experimentar o cliente e o terminal de gerenciamento
Por favor, não altere as funções e permissões padrão à vontade. Por favor, seja gentil e não use nomes muito incivilizados.
Construído usando @vue/cli, o cliente de serviço de IM usa Vant para a parte da UI
Este projeto tem como objetivo principal demonstrar a aplicação básica de um cliente (semelhante ao WeChat. Possui funções como cadastro, login, edição de informações pessoais, adição de amigos, inscrição para ingressar em grupo, bate-papo, etc. Precisa ser utilizado com). o back-end.
Todos estão familiarizados com o projeto Vue Family Bucket (acho que é melhor que React nesse aspecto, e não há tantas opções).
Primeiro, apresente o pacote socket.io-client. Você pode saber pelo nome que ele é a parte cliente do socket.io.
Se quiser enviar e receber informações com o servidor, você deve primeiro estabelecer um link.
import io from 'socket.io-client';
// 首先需要链接上后端的 socket.io,query是链接的参数
this.socket = io('http://127.0.0.1:7001', {
query: {
scene: 'im',
userId: '1'
}
});
// socket.on 就是监听事件,connect就是链接上了服务端
this.socket.on('connect', () => {
console.log('socket连接成功!');
// ....
});
Após o sucesso do link neste projeto, passei a solicitar a lista de sessões e os registros das mensagens, para garantir que o link foi bem sucedido no recebimento da mensagem.
Após conectar-se ao servidor, você pode enviar e receber informações. É muito simples:
// 发送消息,message是自己定义的消息体
this.socket.emit('/v1/im/new-message', message);
// 有新消息收到
this.socket.on('/v1/im/new-message', message => {
// 自己进行一系列的处理
});
O envio e o recebimento de mensagens podem ser combinados com o backend. Mesmo que o frontend envie suas próprias mensagens, ele não será exibido até receber a mensagem do grupo em segundo plano. ser enviado.
Ao inserir, é uma string pura como [酷]
. Ao salvar, também é uma string. Quando exibida, é substituída pelo ícone correspondente. na caixa de entrada. O chefe originalmente me pediu para fazer isso e eu tentei, mas descobri que era um grande buraco. Hoje em dia, parece que apenas a caixa de entrada do Weibo com a qual entrei em contato exibe ícones em vez de strings, o que também gera muitas dúvidas:
Mas é ótimo usar strings (WeChat e DingTalk), todos os recursos nativos podem ser usados e o front-end é fácil de manusear (ponto chave)
Do exposto, podemos ver como o socket.io é conveniente de usar. Primeiro, estabeleça um link e, em seguida, você poderá enviar e receber mensagens. Combinado com nosso cenário de mensagens instantâneas, tomamos as seguintes providências:
/v1/im/new-message
Comumente visto em aplicativos móveis ao rolar e clicar para entrar
Quando desenvolvemos aplicativos da web, muitas vezes encontramos problemas. Quando passamos de uma página de lista rolável para a próxima página de detalhes e depois retornamos à página de lista, é difícil restaurar o estado da barra de rolagem e não conseguimos lembrar. O local onde você se mudou.
Eu tentei muitos métodos antes:
Nenhuma das soluções acima é ideal
Posteriormente, desenvolvi o vue-page-stack com referência ao keep-alive para salvar a pilha de páginas do Vue, ou seja, o dom virtual no Vue, mas o problema da barra de rolagem ainda não foi resolvido. Como o DOM virtual não registra o status de rolagem de cada componente, ele não pode ser restaurado.
Quando usei o cube-ui, descobri que usar o contêiner de rolagem nesta biblioteca de componentes pode restaurar a barra de rolagem. Descobri ainda que esse era o motivo da rolagem melhor do professor Huang Yi.
Observando o código-fonte do bs, descobri que a implementação interna do bs não é a rolagem nativa, mas registra algumas informações de rolagem, as mais importantes das quais são x e y, que são os valores de rolagem que implementei. comportamentos de rolagem por meio da implementação de transformação, ao restaurar o DOM virtual, as informações de rolagem também são restauradas.
No final, vue—page-stack + bs pode realizar perfeitamente a restauração da pilha de páginas.
Esse problema é visto principalmente em consultas como registros de mensagens. Você também encontrará esse problema em programas pequenos.
A maioria das cenas de rolagem são de carregamento pull-up. Durante o carregamento pull-up, o conteúdo carregado aparece abaixo da área de rolagem. Após o carregamento, adicionamos os dados à lista, e Vue e outros são responsáveis por renderizar o conteúdo recém-carregado. para carregar. Puxe para continuar rolando.
Mas em nosso cenário, ao navegar pelos registros de mensagens em uma determinada sessão, precisamos puxar para baixo para carregar mais mensagens. Após carregar, continue puxando para baixo e rolando lentamente para visualizar. Isso leva a um problema muito sério: o conteúdo que aparece após o carregamento suspenso está acima da área de rolagem. Se nenhum processamento for feito, ele irá pular diretamente para o topo do conteúdo recém-carregado após o carregamento, porque a distância de rolagem não aumentou. alterado, o que causa um problema, o que é inconsistente com o que queremos alcançar.
Também pensei em vários métodos, incluindo calcular o comprimento total da mensagem recém-adicionada e depois revertê-la. No entanto, o tipo e a altura da mensagem são inconsistentes e haverá erros no cálculo.
A solução final que pensei foi:
Os dois problemas acima estão refletidos na imagem abaixo e o efeito é OK, como segue:
Como a largura de banda do meu servidor é muito fraca, quero usar o CDN o máximo possível e usar algumas extensões, o que colocará muito menos pressão no servidor. Esta parte do conteúdo pertence à parte do webpack.
// index.html
<script src="https://api.map.baidu.com/getscript?v=3.0&ak=ZHjk59sSOpM1eNWgNWyj9zpyAFTHdL5z"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue-router.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuex.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/vant.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/browser/index.js"></script>
// vue.config.js
externals: {
BMap: 'BMap',
vue: 'Vue',
'vue-router': 'VueRouter',
vuex: 'Vuex',
vant: 'vant',
xgplayer: 'Player'
}
Isso também fez com que meu https mostrasse que não era seguro por causa do SameSite, mas não havia outro jeito.
Os recursos de front-end são gerenciados usando nginx, que atua como um proxy reverso. index.html não é armazenado em cache no front-end. Arquivos estáticos como js e css são fortemente armazenados em cache e compactados com gzip por um mês, e o restante /api. , /public e /socket .io precisam ser encaminhados para o servidor. Meu servidor é executado em http://127.0.0.1:7001. Você precisa prestar atenção à configuração de http e pode ser atualizado para websocket.
O certificado https é um certificado aplicado gratuitamente em https://freessl.cn/ e configurado no nginx
server {
listen 80;
server_name im-client.hezf.online;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
root /data/static/im-client;
index index.html;
try_files $uri $uri/ /index.html;
}
location ~* .(html)$ {
root /data/static/im-client;
access_log off;
add_header Cache-Control no-store;
}
location /static {
access_log off;
root /data/static/im-client;
gzip on;
gzip_buffers 32 8K;
gzip_comp_level 6;
gzip_min_length 100;
gzip_types application/javascript text/css text/xml;
gzip_disable "MSIE [1-6]."; #配置禁用gzip条件,支持正则。此处表示ie6及以下不启用gzip(因为ie低版本不支持)
gzip_vary on;
add_header Cache-Control max-age=2592000;
}
location /api {
proxy_pass http://127.0.0.1:7001;
proxy_connect_timeout 3;
proxy_send_timeout 30;
proxy_read_timeout 30;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto http;
proxy_set_header X-NginX-Proxy true;
client_max_body_size 100m;
}
location /public {
proxy_pass http://127.0.0.1:7001;
proxy_connect_timeout 3;
proxy_send_timeout 30;
proxy_read_timeout 30;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 100m;
}
location /socket.io {
proxy_pass http://127.0.0.1:7001;
proxy_connect_timeout 3;
proxy_send_timeout 30;
proxy_read_timeout 30;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 100m;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
server {
listen 443 ssl;
server_name im-client.hezf.online;
ssl_certificate /etc/nginx/conf.d/hezf-online/im-client.hezf.online_chain.crt;
ssl_certificate_key /etc/nginx/conf.d/hezf-online/im-client.hezf.online_key.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #按照这个协议配置
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4:!DH:!DHE;
ssl_prefer_server_ciphers on;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
root /data/static/im-client;
index index.html;
try_files $uri $uri/ /index.html;
}
location ~* .(html)$ {
root /data/static/im-client;
access_log off;
add_header Cache-Control no-store;
}
location /static {
access_log off;
root /data/static/im-client;
gzip on;
gzip_buffers 32 8K;
gzip_comp_level 6;
gzip_min_length 100;
gzip_types application/javascript text/css text/xml;
gzip_disable "MSIE [1-6]."; #配置禁用gzip条件,支持正则。此处表示ie6及以下不启用gzip(因为ie低版本不支持)
gzip_vary on;
add_header Cache-Control max-age=2592000;
}
location /api {
proxy_pass http://127.0.0.1:7001;
proxy_connect_timeout 3;
proxy_send_timeout 30;
proxy_read_timeout 30;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-NginX-Proxy true;
proxy_redirect off;
client_max_body_size 100m;
}
location /public {
proxy_pass http://127.0.0.1:7001;
proxy_connect_timeout 3;
proxy_send_timeout 30;
proxy_read_timeout 30;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 100m;
}
location /socket.io {
proxy_pass http://127.0.0.1:7001;
proxy_connect_timeout 3;
proxy_send_timeout 30;
proxy_read_timeout 30;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 100m;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}