コメント欄にup、downボタンとそれぞれの比率のバーを設置。
そのコメントがどれだけ支持されているかが一目で分かるようなUIを作成したので
何を考えていたのか、どう実装したかを解説。
↓実装した先のサイト
なろう廃人のすすめ
何を考えていたのか
1、コメントがどれだけ支持されているかを可視化
up,downの比率により、読者の支持を可視化。
コメントを読むべきか読まなくて良いかが分かるようにして
見る人の脳内コストの削減をしたかった。
up,downの比率によってコメントのクラスを付け替えて
色、大きさが変わるようにしてパッと入ってくるようにしている。
2、画面から反応が返ってくるようにしてサイトを楽しくする
画面から反応が返ってくることによって
参加している感を出して、
【参加したくなるサイト】を目指した。
処理の流れ
1、ユーザがボタンを押す
2、jqueryでカウント数を増やす・ボタンを押せなくする
3、ajaxでrailsのコントローラを呼んでコメントのupカラムを+1する
4、ajaxの処理がsuccessで返ってきたときは、バーのwidthをアニメーションで変更する
5、画面からカウント数の比率を取得して、コメントのクラスを付け替える
実際の処理
html部分
【ポイント】
・up_down_rateを取得、comment-level-1~5のクラス分けをしてコメントの見た目を変更
・バーの部分は灰色の背景、青い前面の2つを用意して、青い前面のwidthをup_down_rateの%により制御
.card.my-2.mx-0.border-0
.text-muted.small.p-2
名前: #{comment.name}
-# up,downの比率を取得
- up_down_rate = ((comment.up.to_f) / (comment.up.to_f + comment.down.to_f)) * 100
-# 比率によりクラスを分ける
- if 90 <= up_down_rate
.p-2.comment.comment-level-5
#{comment.comment}
- elsif 70 <= up_down_rate && up_down_rate < 90
.p-2.comment.comment-level-4
#{comment.comment}
- elsif 50 <= up_down_rate && up_down_rate < 70
.p-2.comment.comment-level-3
#{comment.comment}
- elsif 30 <= up_down_rate && up_down_rate < 50
.p-2.comment.comment-level-2
#{comment.comment}
- else
.p-2.comment.comment-level-1
#{comment.comment}
.container.mb-0.mt-3.pr-1
.row.mx-auto.d-flex.justify-content-end.comment-bottom-content
%p.up-contents.mb-0
%a.comment-rating-button.comment-rating-button-up.d-inline-flex.justify-content-center.font-weight-bold{} +
%br
%span{class: "comment-count comment-count-up mb-0"}
- if comment.up != nil
#{comment.up}
- else
0
-# 0で割れないので、分母が0の時で場合分け
- if (comment.up.to_f + comment.down.to_f) != 0
.comment-rating-bar.justify-content-center.m-2.mt-3
-# up, downの比率で青いバーの長さを決定する
.comment-rating-bar-up{style: "width: #{( (comment.up.to_f) / (comment.up.to_f + comment.down.to_f) ) * 100}%;"}
- else
.comment-rating-bar.justify-content-center.m-2
-# up, downがどちらも0の時は50%にする
.comment-rating-bar-up{style: "width: 50%;"}
%p.down-contents.mb-0
%a.comment-rating-button.comment-rating-button-down.d-inline-flex.justify-content-center.font-weight-bold{} -
%br
%span{class: "comment-count comment-count-down mb-0"}
- if comment.down != nil
#{comment.down}
- else
0
.comment-id{style: "display:none"}
#{comment.id}
1、ユーザがボタンを押す
コード前半部分 jqueryでcss弄る部分
・up,downボタンのクラスをpushedに付け替えて、動かないようにする
・upのcountを+1する。
$(".comment-rating-button-up").click(function(){
//upを押された時に、upとdownどちらも動かないようにクラスを付け替える TODO セレクターがダサいから直す。
$(this).removeClass("comment-rating-button-up").addClass("comment-rating-button-up-pushed");
var down_button = $(this).parent().next().next().children(".comment-rating-button-down");
down_button.removeClass("comment-rating-button-down").addClass("comment-rating-button-down-pushed");
var old_up_count = parseInt($(this).siblings(".comment-count-up").text());
$(this).siblings(".comment-count-up").text(old_up_count + 1);
コード中盤 ajax送信部分
コメントのidをhiddenでhtmlに埋め込んであるので、
それをjqueryで取得してajaxで送る。
$.ajax({
url: "comment_count_up",
data: { id : parseInt($(this).parent().siblings(".comment-id").text()) },
dataType: "html",
def comment_count_up
@comment = Comment.find_by(id: params[:id])
if @comment.up == nil
@comment.update(up: 1)
else
@comment.update(up: @comment.up + 1)
end
end
#resourcesの上に書く
get "novels/comment_count_up"
コード後半 コメントのクラス付け替え、バーの長さ変更
・up_down_rateを最初に取得
・rateに応じてcomment-levelを決定
・元のcomment-levelのクラスを削除して、上で定義したcomment-levelをつける
success: (data) => {
var up_count = parseInt($(this).parents(".comment-bottom-content").children(".up-contents").children(".comment-count-up").text());
var down_count = parseInt($(this).parents(".comment-bottom-content").children(".down-contents").children(".comment-count-down").text());
var sum_count = up_count + down_count
var up_down_rate = ((up_count/sum_count)*100)
// 青いバーのwidthをanimeteを使って変更
$(this).parent().next().children(".comment-rating-bar-up").animate({width:up_down_rate + "%"},200);
// rateに応じてcomment_levelを定義
switch(true) {
case 90 <= up_down_rate:
var comment_level = "comment-level-5";
break;
case 70 <= up_down_rate && up_down_rate < 90 :
var comment_level = "comment-level-4";
break;
case 50 <= up_down_rate && up_down_rate < 70 :
var comment_level = "comment-level-3";
break;
case 30 <= up_down_rate && up_down_rate < 50 :
var comment_level = "comment-level-2";
break;
case up_down_rate < 30 :
var comment_level = "comment-level-1";
break;
default:
alert("0より小さいです");
}
//前方一致でクラスを削除 参考:jQueryの.removeClass()で「特定の文字列で始まるclass」をすべて削除する
//comment_levelのクラスを付け加える
$(this).parents(".card").children(".comment").removeClass(function(index, className) {
return (className.match(/\bcomment-level-\S+/g) || []).join(' ');
}).addClass(comment_level);
console.log("正常にup完了")
},
javascriptコード全体(upボタンを押された場合)
//upボタン押された時
$(document).on('turbolinks:load',function(){
$(".comment-rating-button-up").click(function(){
//upを押された時に、upとdownどちらも動かないようにクラスを付け替える TODO セレクターがダサいから直す。
$(this).removeClass("comment-rating-button-up").addClass("comment-rating-button-up-pushed");
var down_button = $(this).parent().next().next().children(".comment-rating-button-down");
down_button.removeClass("comment-rating-button-down").addClass("comment-rating-button-down-pushed");
var old_up_count = parseInt($(this).siblings(".comment-count-up").text());
$(this).siblings(".comment-count-up").text(old_up_count + 1);
$.ajax({
url: "comment_count_up",
data: { id : parseInt($(this).parent().siblings(".comment-id").text()) },
dataType: "html",
success: (data) => {
//TODO function get_up_down_rateに切り出ししたい
var up_count = parseInt($(this).parents(".comment-bottom-content").children(".up-contents").children(".comment-count-up").text());
var down_count = parseInt($(this).parents(".comment-bottom-content").children(".down-contents").children(".comment-count-down").text());
var sum_count = up_count + down_count
var up_down_rate = ((up_count/sum_count)*100)
$(this).parent().next().children(".comment-rating-bar-up").animate({width:up_down_rate + "%"},200);
switch(true) {
case 90 <= up_down_rate:
var comment_level = "comment-level-5";
break;
case 70 <= up_down_rate && up_down_rate < 90 :
var comment_level = "comment-level-4";
break;
case 50 <= up_down_rate && up_down_rate < 70 :
var comment_level = "comment-level-3";
break;
case 30 <= up_down_rate && up_down_rate < 50 :
var comment_level = "comment-level-2";
break;
case up_down_rate < 30 :
var comment_level = "comment-level-1";
break;
default:
alert("0より小さいです");
}
//前方一致でクラスを削除 参考:jQueryの.removeClass()で「特定の文字列で始まるclass」をすべて削除する
$(this).parents(".card").children(".comment").removeClass(function(index, className) {
return (className.match(/\bcomment-level-\S+/g) || []).join(' ');
}).addClass(comment_level);
console.log("正常にup完了")
},
error: function(data) {
console.log('upをつけるのに失敗しています');
}
});
});
});
CSS
ポイント
・押した後のボタンはpointer-events: none;を入れて押せなくする。
.comment-rating-button {
display: block;
width: 30px;
height: 30px;
border-radius: 15px;
font-size: 25px;
padding-top: 5px;
margin-bottom: 1px;
// ユーザーがボタンのテキストをハイライトできないようにする
-webkit-user-select:none;
-moz-user-select:none;
-ms-user-select:none;
user-select:none;
}
.comment-rating-button-up{
background: #73DCFF;
box-shadow: 0 2px 0 #2a82a3;
color: white !important;
&:hover{
background-color: #2a82a3 !important;
}
}
.comment-rating-button-up-pushed{
background-color: #2a82a3 !important;
box-shadow: 0 2px 0 #2a82a3;
color: white !important;
pointer-events: none;
&:hover{
background-color: #2a82a3 !important;
}
}
.comment-rating-button-down{
background: #BDBDAE;
box-shadow: 0 3px 0 #79796A;
color: white !important;
&:hover{
background-color: #79796A !important;
}
}
.comment-rating-button-down-pushed{
background-color: #79796A !important;
box-shadow: 0 3px 0 #79796A;
color: white !important;
pointer-events: none;
&:hover{
background-color: #79796A !important;
}
}
.comment-rating-bar{
border-radius: 20px;
background-color: #DFDFD0;
height: 15px;
width: 150px;
.comment-rating-bar-up{
border-radius: 20px;
background-color: #73DCFF;
height: 15px;
width: 100px;
}
}
.comment-count{
font-size: 12px;
margin-left: 8px;
}
.comment-count-up{
color: #5DB2CD !important;
}
.comment-count-down{
color: #99998C !important;
}
// up_down_rate = 90%~
.comment-level-5{
font-size: 150%;
font-weight: bold;
color: red;
}
// up_down_rate = 70~90%
.comment-level-4{
font-size: 130%;
font-weight: bold;
}
// up_down_rate = 50~70%
.comment-level-3{
font-weight: bold;
}
// up_down_rate = 30=50%
.comment-level-2{
}
// up_down_rate = ~ 30%
.comment-level-1{
color: #777;
}