翼度科技»论坛 编程开发 JavaScript 查看内容

利用Vue+ElementUi实现评论功能

10

主题

10

帖子

30

积分

新手上路

Rank: 1

积分
30
前言

这两天在用vue重构之前写的一个社区博客项目,之前评论的样式和效果都差强人意,所以仿照掘金重写了一个评论功能(但不是完全照搬模仿)
在写完这个功能后,由心觉得Vue真的非常好用。
话不多说,先上效果图




代码

html代码:
  1. <template>
  2.     <div>
  3.         <div v-clickoutside="hideReplyBtn" @click="inputFocus" class="my-reply">
  4.             <el-avatar class="header-img" :size="40" :src="myHeader"></el-avatar>
  5.             <div class="reply-info" >
  6.                 <div
  7.                 tabindex="0"
  8.                 contenteditable="true"
  9.                 id="replyInput"
  10.                 spellcheck="false"
  11.                 placeholder="输入评论..."
  12.                 class="reply-input"
  13.                 @focus="showReplyBtn"  
  14.                 @input="onDivInput($event)"
  15.                 >
  16.                 </div>
  17.             </div>
  18.             <div class="reply-btn-box" v-show="btnShow">
  19.                 <el-button class="reply-btn" size="medium" @click="sendComment" type="primary">发表评论</el-button>
  20.             </div>
  21.         </div>
  22.         <div v-for="(item,i) in comments" :key="i" class="author-title reply-father">
  23.             <el-avatar class="header-img" :size="40" :src="item.headImg"></el-avatar>
  24.             <div class="author-info">
  25.                 <span class="author-name">{{item.name}}</span>
  26.                 <span class="author-time">{{item.time}}</span>
  27.             </div>
  28.             <div class="icon-btn">
  29.                 <span @click="showReplyInput(i,item.name,item.id)"><i class="iconfont el-icon-s-comment"></i>{{item.commentNum}}</span>
  30.                 <i class="iconfont el-icon-caret-top"></i>{{item.like}}
  31.             </div>
  32.             <div class="talk-box">
  33.                 <p>
  34.                     <span class="reply">{{item.comment}}</span>
  35.                 </p>
  36.             </div>
  37.             <div class="reply-box">
  38.                 <div v-for="(reply,j) in item.reply" :key="j" class="author-title">
  39.                     <el-avatar class="header-img" :size="40" :src="reply.fromHeadImg"></el-avatar>
  40.                     <div class="author-info">
  41.                         <span class="author-name">{{reply.from}}</span>
  42.                         <span class="author-time">{{reply.time}}</span>
  43.                     </div>
  44.                     <div class="icon-btn">
  45.                         <span @click="showReplyInput(i,reply.from,reply.id)"><i class="iconfont el-icon-s-comment"></i>{{reply.commentNum}}</span>
  46.                         <i class="iconfont el-icon-caret-top"></i>{{reply.like}}
  47.                     </div>
  48.                     <div class="talk-box">
  49.                         <p>
  50.                             <span>回复 {{reply.to}}:</span>
  51.                             <span class="reply">{{reply.comment}}</span>
  52.                         </p>
  53.                     </div>
  54.                     <div class="reply-box">

  55.                     </div>
  56.                 </div>
  57.             </div>
  58.             <div  v-show="_inputShow(i)" class="my-reply my-comment-reply">
  59.                 <el-avatar class="header-img" :size="40" :src="myHeader"></el-avatar>
  60.                 <div class="reply-info" >
  61.                     <div tabindex="0" contenteditable="true" spellcheck="false" placeholder="输入评论..."   @input="onDivInput($event)"  class="reply-input reply-comment-input"></div>
  62.                 </div>
  63.                 <div class=" reply-btn-box">
  64.                     <el-button class="reply-btn" size="medium" @click="sendCommentReply(i,j)" type="primary">发表评论</el-button>
  65.             </div>
  66.         </div>
  67.         </div>
  68.     </div>
  69. </template>
复制代码
JS代码如下
我把模拟的数据写在了data里面,显得js有点长。如果要更改数据的格式的话,记得也要改Html不然会出错。
  1. <script>
  2. const clickoutside = {
  3.     // 初始化指令
  4.     bind(el, binding, vnode) {
  5.     function documentHandler(e) {
  6.     // 这里判断点击的元素是否是本身,是本身,则返回
  7.         if (el.contains(e.target)) {
  8.             return false;
  9.         }
  10.     // 判断指令中是否绑定了函数
  11.         if (binding.expression) {
  12.             // 如果绑定了函数 则调用那个函数,此处binding.value就是handleClose方法
  13.             binding.value(e);
  14.         }
  15.     }
  16.     // 给当前元素绑定个私有变量,方便在unbind中可以解除事件监听
  17.     el.vueClickOutside = documentHandler;
  18.     document.addEventListener('click', documentHandler);
  19.     },
  20.     update() {},
  21.     unbind(el, binding) {
  22.     // 解除事件监听
  23.     document.removeEventListener('click', el.vueClickOutside);
  24.     delete el.vueClickOutside;
  25.   },
  26. };
  27. export default {
  28.     name:'ArticleComment',
  29.     data(){
  30.         return{
  31.             btnShow: false,
  32.             index:'0',
  33.             replyComment:'',
  34.             myName:'Lana Del Rey',
  35.             myHeader:'https://ae01.alicdn.com/kf/Hd60a3f7c06fd47ae85624badd32ce54dv.jpg',
  36.             myId:19870621,
  37.             to:'',
  38.             toId:-1,
  39.             comments:[
  40.                 {
  41.                     name:'Lana Del Rey',
  42.                     id:19870621,
  43.                     headImg:'https://ae01.alicdn.com/kf/Hd60a3f7c06fd47ae85624badd32ce54dv.jpg',
  44.                     comment:'我发布一张新专辑Norman Fucking Rockwell,大家快来听啊',
  45.                     time:'2019年9月16日 18:43',
  46.                     commentNum:2,
  47.                     like:15,
  48.                     inputShow:false,
  49.                     reply:[
  50.                         {
  51.                             from:'Taylor Swift',
  52.                             fromId:19891221,
  53.                             fromHeadImg:'https://ae01.alicdn.com/kf/H94c78935ffa64e7e977544d19ecebf06L.jpg',
  54.                             to:'Lana Del Rey',
  55.                             toId:19870621,
  56.                             comment:'我很喜欢你的新专辑!!',
  57.                             time:'2019年9月16日 18:43',
  58.                             commentNum:1,
  59.                             like:15,
  60.                             inputShow:false
  61.                         },
  62.                         {
  63.                             from:'Ariana Grande',
  64.                             fromId:1123,
  65.                             fromHeadImg:'https://ae01.alicdn.com/kf/Hf6c0b4a7428b4edf866a9fbab75568e6U.jpg',
  66.                             to:'Lana Del Rey',
  67.                             toId:19870621,
  68.                             comment:'别忘记宣传我们的合作单曲啊',
  69.                             time:'2019年9月16日 18:43',
  70.                             commentNum:0,
  71.                             like:5,
  72.                             inputShow:false

  73.                         }
  74.                     ]
  75.                 },
  76.                 {
  77.                     name:'Taylor Swift',
  78.                     id:19891221,
  79.                     headImg:'https://ae01.alicdn.com/kf/H94c78935ffa64e7e977544d19ecebf06L.jpg',
  80.                     comment:'我发行了我的新专辑Lover',
  81.                     time:'2019年9月16日 18:43',
  82.                     commentNum:1,
  83.                     like:5,
  84.                     inputShow:false,
  85.                     reply:[
  86.                         {
  87.                             from:'Lana Del Rey',
  88.                             fromId:19870621,
  89.                             fromHeadImg:'https://ae01.alicdn.com/kf/Hd60a3f7c06fd47ae85624badd32ce54dv.jpg',
  90.                             to:'Taylor Swift',
  91.                             toId:19891221,
  92.                             comment:'新专辑和speak now 一样棒!',
  93.                             time:'2019年9月16日 18:43',
  94.                             commentNum:25,
  95.                             like:5,
  96.                             inputShow:false

  97.                         }
  98.                     ]
  99.                 },
  100.                 {
  101.                     name:'Norman Fucking Rockwell',
  102.                     id:20190830,
  103.                     headImg:'https://ae01.alicdn.com/kf/Hdd856ae4c81545d2b51fa0c209f7aa28Z.jpg',
  104.                     comment:'Plz buy Norman Fucking Rockwell on everywhere',
  105.                     time:'2019年9月16日 18:43',
  106.                     commentNum:0,
  107.                     like:5,
  108.                     inputShow:false,
  109.                     reply:[]
  110.                 },
  111.             ]
  112.         }
  113.     },
  114.     directives: {clickoutside},
  115.     methods: {
  116.         inputFocus(){
  117.             var replyInput = document.getElementById('replyInput');
  118.             replyInput.style.padding= "8px 8px"
  119.             replyInput.style.border ="2px solid blue"
  120.             replyInput.focus()
  121.         },  
  122.         showReplyBtn(){
  123.             this.btnShow = true
  124.         },
  125.         hideReplyBtn(){
  126.             this.btnShow = false
  127.             replyInput.style.padding= "10px"
  128.             replyInput.style.border ="none"
  129.         },
  130.         showReplyInput(i,name,id){
  131.             this.comments[this.index].inputShow = false
  132.             this.index =i
  133.             this.comments[i].inputShow = true
  134.             this.to = name
  135.             this.toId = id
  136.         },
  137.         _inputShow(i){
  138.             return this.comments[i].inputShow
  139.         },
  140.         sendComment(){
  141.             if(!this.replyComment){
  142.                  this.$message({
  143.                     showClose: true,
  144.                     type:'warning',
  145.                     message:'评论不能为空'
  146.                 })
  147.             }else{
  148.                 let a ={}
  149.                 let input =  document.getElementById('replyInput')
  150.                 let timeNow = new Date().getTime();
  151.                 let time= this.dateStr(timeNow);
  152.                 a.name= this.myName
  153.                 a.comment =this.replyComment
  154.                 a.headImg = this.myHeader
  155.                 a.time = time
  156.                 a.commentNum = 0
  157.                 a.like = 0
  158.                 this.comments.push(a)
  159.                 this.replyComment = ''
  160.                 input.innerHTML = '';

  161.             }
  162.         },
  163.         sendCommentReply(i,j){
  164.             if(!this.replyComment){
  165.                  this.$message({
  166.                     showClose: true,
  167.                     type:'warning',
  168.                     message:'评论不能为空'
  169.                 })
  170.             }else{
  171.                 let a ={}
  172.                 let timeNow = new Date().getTime();
  173.                 let time= this.dateStr(timeNow);
  174.                 a.from= this.myName
  175.                 a.to = this.to
  176.                 a.fromHeadImg = this.myHeader
  177.                 a.comment =this.replyComment
  178.                 a.time = time
  179.                 a.commentNum = 0
  180.                 a.like = 0
  181.                 this.comments[i].reply.push(a)
  182.                 this.replyComment = ''
  183.                 document.getElementsByClassName("reply-comment-input")[i].innerHTML = ""
  184.             }
  185.         },
  186.         onDivInput: function(e) {
  187.             this.replyComment = e.target.innerHTML;
  188.         },
  189.         dateStr(date){
  190.             //获取js 时间戳
  191.             var time=new Date().getTime();
  192.             //去掉 js 时间戳后三位,与php 时间戳保持一致
  193.             time=parseInt((time-date)/1000);
  194.             //存储转换值
  195.             var s;
  196.             if(time<60*10){//十分钟内
  197.                 return '刚刚';
  198.             }else if((time<60*60)&&(time>=60*10)){
  199.                 //超过十分钟少于1小时
  200.                 s = Math.floor(time/60);
  201.                 return  s+"分钟前";
  202.             }else if((time<60*60*24)&&(time>=60*60)){
  203.                 //超过1小时少于24小时
  204.                 s = Math.floor(time/60/60);
  205.                 return  s+"小时前";
  206.             }else if((time<60*60*24*30)&&(time>=60*60*24)){
  207.                 //超过1天少于30天内
  208.                 s = Math.floor(time/60/60/24);
  209.                 return s+"天前";
  210.             }else{
  211.                 //超过30天ddd
  212.                 var date= new Date(parseInt(date));
  213.                 return date.getFullYear()+"/"+(date.getMonth()+1)+"/"+date.getDate();
  214.             }
  215.         }
  216.     },   
  217. }
  218. </script>
复制代码
css 代码
  1. <style lang="stylus" scoped>
  2. .my-reply
  3.     padding 10px
  4.     background-color #fafbfc
  5.     .header-img
  6.         display inline-block
  7.         vertical-align top
  8.     .reply-info   
  9.         display inline-block
  10.         margin-left 5px
  11.         width 90%
  12.         @media screen and (max-width:1200px) {
  13.             width 80%
  14.         }
  15.         .reply-input
  16.             min-height 20px
  17.             line-height 22px
  18.             padding 10px 10px
  19.             color #ccc
  20.             background-color #fff
  21.             border-radius 5px
  22.             &:empty:before
  23.                 content attr(placeholder)
  24.             &:focus:before
  25.                 content none
  26.             &:focus
  27.                 padding 8px 8px
  28.                 border 2px solid blue
  29.                 box-shadow none
  30.                 outline none
  31.     .reply-btn-box
  32.         height 25px
  33.         margin 10px 0
  34.         .reply-btn
  35.             position relative
  36.             float right
  37.             margin-right 15px
  38. .my-comment-reply
  39.     margin-left 50px
  40.     .reply-input
  41.         width flex
  42. .author-title:not(:last-child)
  43.     border-bottom: 1px solid rgba(178,186,194,.3)
  44. .author-title
  45.     padding 10px
  46.     .header-img
  47.         display inline-block
  48.         vertical-align top
  49.     .author-info
  50.         display inline-block
  51.         margin-left 5px
  52.         width 60%
  53.         height 40px
  54.         line-height 20px
  55.         >span
  56.             display block
  57.             cursor pointer
  58.             overflow hidden
  59.             white-space nowrap
  60.             text-overflow ellipsis
  61.         .author-name
  62.             color #000
  63.             font-size 18px
  64.             font-weight bold
  65.         .author-time
  66.             font-size 14px
  67.     .icon-btn
  68.         width 30%
  69.         padding 0 !important
  70.         float right
  71.         @media screen and (max-width : 1200px){
  72.             width 20%
  73.             padding 7px
  74.         }
  75.         >span
  76.             cursor pointer
  77.         .iconfont
  78.             margin 0 5px
  79.     .talk-box
  80.         margin 0 50px
  81.         >p
  82.            margin 0
  83.         .reply
  84.             font-size 16px
  85.             color #000
  86.     .reply-box
  87.         margin 10px 0 0 50px
  88.         background-color #efefef
  89. </style>
复制代码
写在最后

如果代码有什么问题,或者你有什么意见,欢迎大家指出。
到此这篇关于利用Vue+ElementUi实现评论功能的文章就介绍到这了,更多相关Vue ElementUi评论内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

来源:https://www.jb51.net/javascript/3192092e3.htm
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
来自手机

举报 回复 使用道具