--Mise en œuvre en utilisant le canal --Afficher les commentaires de manière asynchrone
Un canal est un mécanisme côté serveur qui fournit une fonctionnalité de mise à jour immédiate. Définissez l'itinéraire des données et affichez les données envoyées sur l'écran du client.
Si vous définissez l'itinéraire des données ou écrivez du JavaScript pour afficher les données envoyées, les données envoyées peuvent être affichées de manière asynchrone.
Exécutez la commande suivante dans le terminal
% rails g channel comment
(Entrez le nom du fichier que vous créez dans comment
)
Il existe plusieurs fichiers, mais cette fois, nous utiliserons les deux fichiers suivants.
app/channel/comment_channel.rb
Un fichier qui connecte le client et le serveur.
app/javascript/channels/comment_channel.js Il s'agit d'un fichier permettant d'afficher les données envoyées depuis le serveur sur l'écran client.
class MessageChannel < ApplicationCable::Channel
def subscribed
stream_from "comment_channel"
end
def unsubscribed
end
end
Vous pouvez connecter le serveur et le client en écrivant stream_from" comment_channel "
.
Une description du contrôleur. Étant donné que la fonction d'implémentation de commentaire qui n'est pas asynchrone est déjà terminée, les explications autres que la description liée à asynchrone sont omises.
Les données que je veux refléter dans JS cette fois sont les suivantes
Il est nécessaire de transmettre ces trois informations à JS par le contrôleur.
class CommentsController < ApplicationController
before_action :authenticate_user!
def create
@comment = Comment.new(comment_params)
@item = Item.find(params[:item_id])
@comments = @item.comments.includes(:user).order('created_at DESC')
if @comment.valid?
@comment.save
ActionCable.server.broadcast 'comment_channel', content: @comment, nickname: @comment.user.nickname, time: @comment.created_at.strftime("%Y/%m/%d %H:%M:%S"), id: @item.id
else
render "items/show"
end
end
private
def comment_params
params.require(:comment).permit(:text).merge(user_id: current_user.id, item_id: params[:item_id])
end
end
Seule la phrase suivante a été ajoutée dans cette implémentation.
ActionCable.server.broadcast 'comment_channel', content: @comment, nickname: @comment.user.nickname, time: @comment.created_at.strftime("%Y/%m/%d %H:%M:%S"), id: @item.id
Puisque content
, ʻuser,
time et ʻid
sont utilisés dans JS, je les ai définis.
content
Défini par @comment: text, la colonne de texte de la table Commentaire, c'est-à-dire le commentaire que vous avez entré.
user
Le surnom de l'utilisateur associé à @comment est récupéré. (Nous avons une association avec le commentaire et l'utilisateur.)
time
La colonne created_at de la table Comment. Tout paramètre de date et d'heure peut être affiché en écrivant strftime ("% Y /% m /% d% H:% M:% S ")
. J'ai fait référence à l'article suivant.
Je ne me souviens pas de strftime (ruby)
item
JS doit se déclencher uniquement sur la page de l'élément que vous consultez actuellement, utilisez-le pour le déterminer.
Cette fois, nous le décrirons dans la partie receive ()
de ʻapp / javascript / channels / comment_channel.js`.
app/javascript/channels/comment_channel.js
received(data) {
}
En écrivant «data» dans (), la valeur définie par le contrôleur peut être obtenue. «Reçu» signifie recevoir, donc lorsque vous recevez les données, exécutez le JS qui y est décrit! Cela signifie que. Maintenant, je vais décrire JS dans ceci!
app/javascript/channels/comment_channel.js
//Obtenez l'URL de la page actuellement ouverte
let url = window.location.href
//Sabrer(/)Extraire des éléments pour chacun
let param = url.split('/');
//Dans le cas de cette application, l'identifiant de l'élément se trouve à la toute fin de l'URL et il est défini comme paramItem.
let paramItem = param[param.length-1]
//ID de paramètre(L'identifiant contenu dans l'URL)Envoyé par le contrôleur`data.id`Déterminez si
if (paramItem == data.id) {}
Le branchement conditionnel est effectué avec l'instruction if. Ensuite, j'écrirai le contenu du processus dans la branche conditionnelle. Le contenu à décrire est
--Créer un élément div --Afficher l'élément généré sur le navigateur --Générer le texte à afficher
C'est un flux comme.
app/javascript/channels/comment_channel.js
//Obtenez l'ID du div du lieu à afficher
const comments = document.getElementById('comments');
//Créer un div pour être identique à un fichier de vue existant
const textElement = document.createElement('div');
textElement.setAttribute('class', "comment-display");
const topElement = document.createElement('div');
topElement.setAttribute('class', "comment-top");
const nameElement = document.createElement('div');
const timeElement = document.createElement('div');
const bottomElement = document.createElement('div');
bottomElement.setAttribute('class', "comment-bottom");
Utilisez la méthode createElement pour créer un élément div et attribuez à chaque nom de classe requis la méthode setAttribute.
Au fait, la vue pour afficher les commentaires est la suivante
<div id='comments'>
</div>
<% @comments.each do |comment| %>
<div class='comment-display'>
<div class='comment-top'>
<div><%= comment.user.nickname %></div>
<div><%= l comment.created_at %></div>
</div>
<div class='comment-bottom'>
<p><%= comment.text %></p>
</div>
</div>
<% end %>
J'ai généré un élément div, mais il n'est pas encore visible dans le navigateur. Affichons-le sur le navigateur et créons une relation parent-enfant.
app/javascript/channels/comment_channel.js
//Afficher l'élément HTML généré sur le navigateur
comments.insertBefore(textElement, comments.firstElementChild);
textElement.appendChild(topElement);
textElement.appendChild(bottomElement);
topElement.appendChild(nameElement);
topElement.appendChild(timeElement);
Utilisez la méthode insertBefire et la méthode appendChild. Parent element.insertBefore (élément à ajouter, où ajouter) Élément parent .appendChild (élément à ajouter) Ainsi insertBefire peut placer un élément n'importe où, et appendChild peut mettre un élément à la fin de la classe parent.
Si vous voulez voir un peu plus de détails, veuillez voir ci-dessous [JavaScript] Différence entre appendChild et insertBefore
Après avoir créé l'élément div, obtenons les informations à afficher.
app/javascript/channels/comment_channel.js
const name = `${data.nickname}`;
nameElement.innerHTML = name;
const time = `${data.time}`;
timeElement.innerHTML = time;
const text = `<p>${data.content.text}</p>`;
bottomElement.innerHTML = text;
Les informations à afficher sont mises dans chaque variable. les données sont les données pour reçues (données) {}
. C'est la valeur définie dans le contrôleur. Vous avez défini respectivement «content», «nickname» et «time».
Remplacez les éléments existants par innerHTML.
L'affichage est complet jusqu'à présent! Cependant, il y a deux problèmes à ce rythme.
app/javascript/channels/comment_channel.js
const newComment = document.getElementById('comment_text');
newComment.value='';
C'est une description que l'ID du champ de saisie de commentaire est récupéré et la valeur qui s'y trouve est vidée.
app/javascript/channels/comment_channel.js
const inputElement = document.querySelector('input[name="commit"]');
inputElement.disabled = false;
Vous pouvez cliquer dessus plusieurs fois en récupérant l'attribut de nom du bouton "Commentaire" et en le définissant comme disabled = false
.
app/javascript/channels/comment_channel.js
import consumer from "./consumer"
consumer.subscriptions.create("CommentChannel", {
connected() {
},
disconnected() {
},
//↓ Lorsque vous recevez les données, exécutez-les.
received(data) {
let url = window.location.href
let param = url.split('/');
let paramItem = param[param.length-1]
if (paramItem == data.id) {
const comments = document.getElementById('comments');
const comment = document.getElementsByClassName('comment-display');
//Créer des éléments à utiliser
const textElement = document.createElement('div');
textElement.setAttribute('class', "comment-display");
const topElement = document.createElement('div');
topElement.setAttribute('class', "comment-top");
const nameElement = document.createElement('div');
const timeElement = document.createElement('div');
const bottomElement = document.createElement('div');
bottomElement.setAttribute('class', "comment-bottom");
//Afficher l'élément HTML généré sur le navigateur
comments.insertBefore(textElement, comments.firstElementChild);
textElement.appendChild(topElement);
textElement.appendChild(bottomElement);
topElement.appendChild(nameElement);
topElement.appendChild(timeElement);
//Générer du texte à afficher
const name = `${data.nickname}`;
nameElement.innerHTML = name;
const time = `${data.time}`;
timeElement.innerHTML = time;
const text = `<p>${data.content.text}</p>`;
bottomElement.innerHTML = text;
//Après avoir envoyé un commentaire, laissez le champ de commentaire vide
const newComment = document.getElementById('comment_text');
newComment.value='';
//Vous permet d'appuyer plusieurs fois sur le bouton
const inputElement = document.querySelector('input[name="commit"]');
inputElement.disabled = false;
}
}
});
Je pensais que c'était terminé, mais au moment de la rédaction de cet article, j'ai trouvé un certain nombre d'erreurs et des descriptions peu claires. Je comprends à quel point le refactoring est important. Il peut y avoir des descriptions incorrectes, mais j'espère que cela aide quelqu'un.
Recommended Posts