• 从零开始利用vue-cli搭建简单音乐网站(八)


    这是完成了预想中的最后两个功能:歌曲评论以及歌曲搜索。

    1、评论效果:

    用户点击评论按钮,评论框获取焦点。

    输入之后点击提交,下方显示评论,用户名称以及日期。相应的用户也可以删除自己评论。

    当然只能删除自己的评论,鼠标放置其他人评论上面不会显示删除按钮。

    2、搜索歌曲

    搜索可以搜索歌曲或者歌手,这里搜索"LiSA",结果如下:

    也可以只输入“A”,显示如下:

    这里有一个歌手页面,显示的是所有歌手的歌曲,如点击"Aimer"歌手:

    至此,基本功能就展示完成,下面看实现。

    先是评论功能,在评论按钮监听点击事件:“<button class="btn" @click="focusToComment">评论</button>”

    focusToComment事件,id=comment就是评论输入框:

    focusToComment: function() {
                    // 点击跳转评论
                    document.getElementById("comment").focus()
                },

    然后是输入框提交按钮监听事件:“<input type="button" id="submitBtn" name="submitBtn" value="评论" @click="submitComment" />”

    submitComment事件提交所输入的评论,实现如下:

                submitComment: function() {
    
                    if(this.PlayMusicMsg.username == "") {
                        alert("请先登录")
                    } else {
                        // 这里把评论,用户名,评论日期作为一个对象,然后和歌曲名称一起作为对象传递给后台
                        var message = this.message
                        var username = this.PlayMusicMsg.username
    
                        // 这里获取当前时间
                        var date = new Date()
                        var year = date.getFullYear()
                        var month = date.getMonth() + 1
                        var day = date.getDate()
                        var commentDate = year + "年" + month + "月" + day + "日"
    
                        var musicName = this.music.name
    
                        var commentObj = {
                            message: message,
                            username: username,
                            commentDate: commentDate,
                            pos: 0
                        }
                        var commentData = {
                            musicName: musicName,
                            commentObj: commentObj
                        }
    
                        // 发送请求
                        this.$http.post('/query/insertMusicComment', commentData).then(function(response) {
                            if(response.body.errno === 0) {
                                // 成功,更新界面
                                var newpos = response.body.data
                                var commentObj = {
                                    message: message,
                                    username: username,
                                    commentDate: commentDate,
                                    pos: newpos
                                }
                                this.comments.push(commentObj)
                                alert("评论成功")
                            }
                        })
                    }
                },

    先是利用App.vue页面传递过来的PlayMusicMsg参数检测用户名是否存在,不存在表示还没有登录,所以提示先登录。然后登陆的话,把用户名username,评论message,评论日期Date封装为commentObj对象,注意该对象还有一个pos,表示评论位置,这是我实现评论删除的思路,因为每一首歌曲下面只有一个评论数组,所以后面只需要找到对应pos的评论就可以从数据库去除。接着把commentObj对象和歌曲名musicName封装在一起发送给后台,成功的话用this.comments.push(commentObj)把评论显示在页面上。

    接着是后台处理评论数据,如下:

    // 插入歌曲评论
    queryRoutes.post('/insertMusicComment', function(req, res) {
        var musicName = req.body.musicName
        var commentObj = req.body.commentObj
    
        musicCommentModel.find({
            musicName: musicName
        }, function(error, data) {
            console.log(data)
            if(data[0] != null) {
                // 数据存在,更新
                // 这里给每个评论添加一个序号
                var length = data[0].comments.length
                var pos;
                if(length === 0) {
                    pos = 1
                } else {
                    var last = data[0].comments.length - 1
                    pos = data[0].comments[last].pos + 1
                }
                commentObj.pos = pos
                data[0].comments.push(commentObj)
    
                musicCommentModel.update({
                    musicName: musicName
                }, {
                    comments: data[0].comments
                }, function(error, data) {
                    res.send({
                        errno: 0,
                        data: pos
                    })
                })
            } else {
                // 数据不存在,插入
                var comments = []
                commentObj.pos = 1
                comments.push(commentObj)
                var musicCommentEntity = new musicCommentModel({
                    musicName: musicName,
                    comments: comments
                })
                musicCommentEntity.save({}, function(error, data) {
                    res.send({
                        errno: 0,
                        data: pos
                    })
                })
            }
        })
    })

    先获取到musicName和commentObj,利用find方法查找musicName是否存在,存在则更新数据。先获取该musicName下的评论数组的长度length,如果length=0,则pos设置为1,也就是将要插入的评论的序号,这也是为了将来删除所用。如果length不等于0那么pos等于评论数组最后一位的pos+1。接着利用data[0].comments.push(commentObj)把评论插入数组最后,最后利用update方法更新数据库。另一种情况,如果查找的musicName不存在的时候,pos设置为1,评论插入新数组comments.push(commentObj),新建musicCommentEntity实体,用其save方法保存到数据库。

    下面是删除功能,在PlayMusic.vue页面,监听每一个评论项<li @mouseenter="show(index,value.username)" @mouseleave="hide" id="each-comment">,show方法显示“删除评论“字样,hide隐藏。实现如下:

    <!--这里是删除评论元素绑定-->
    <span v-show="index === i" @click="delComment(value.pos)" id="del-comment">删除评论</span>

    show: function(index, username) { // 显示删除按钮,但是先判断当前用户名和评论用户名是否相等 if(this.PlayMusicMsg.username === username) { this.i = index } }, hide: function() { // 隐藏删除按钮 this.i = -1 },

    这里的删除元素处绑定的是v-show="index===i",因为这是在一个v-for循环中,index是循环序号,i默认值为-1,当show事件触发的时候,把所有i赋值为index,也就是触发show事件的元素所在的序号,那么自然只有该元素的index才等于i,也就会显示出”删除按钮“了,具体可以参考博客:https://segmentfault.com/q/1010000005160077

    这里用户点击删除按钮时候触发delComment事件,事件传递一个参数value.pos,也就是我上面保存时候所说的pos,这里的pos和数据库中的是一一对应的。delComment事件实现如下:

                delComment: function(pos) {
    
                    // 删除评论
                    var delCommentData = {
                        musicName: this.music.name,
                        pos: pos
                    }
                    this.$http.post('/query/delComment', delCommentData).then(function(response) {
                        if(response.body.errno === 0) {
                            // 删除成功,更新界面
                            var comments = this.comments
                            console.log(comments)
                            for(var key in comments) {
                                if(comments[key].pos === pos) {
                                    comments.splice(key, 1)
                                    break
                                }
                            }
                            this.comments = comments
                        }
                    })
                }

    实现很简单,封装delCommentData对象,musicName和pos,发送请求,成功的话界面也更新,更新思路是利用pos找到删除评论所在位置,用splice方法删除,更新。接着是后台接收请求然后实现的代码:

    // 删除歌曲评论
    queryRoutes.post('/delComment', function(req, res) {
        var musicName = req.body.musicName
        var pos = req.body.pos
    
        musicCommentModel.find({
            musicName: musicName
        }, function(error, data) {
            var comments = data[0].comments
            for(var key in comments) {
                if(comments[key].pos === pos) {
                    comments.splice(key, 1)
                    break
                }
            }
            musicCommentModel.update({
                musicName: musicName
            }, {
                comments: comments
            }, function(error, data) {
                res.send({
                    errno: 0,
                    data: data
                })
            })
    
        })
    })

    后台的思路其实是一样的,根据pos找到序号,删除,再用update更新。

    评论功能之后,是歌曲搜索功能。实现思路是利用了mongoose的模糊搜索,匹配一个正则表达式对象,如果数据包含所匹配的字符串则返回,如下:

    // 关键词搜索音乐
    queryRoutes.post('/search', function(req, res) {
        var searchStr = req.body.str
        var reg = new RegExp(searchStr)
        // 关键词索引
        musicDataModel.find({
            $or: [{
                name: reg
            }, {
                singer: reg
            }]
        }, function(error, data) {
            res.send({
                errno: 0,
                data: data
            })
        })
    })

    以上就是搜索的全部实现要点了,注意musicDataModel.find()方法里面的$or,这是mongoose提供的选择查找,属性值是一个数组,这里我分别查找了name和singer两个数据,也就是根据关键词匹配歌曲名称或者匹配歌手,参考链接:https://segmentfault.com/a/1190000008161345

    然后返回前台,前台接收到数据更新在页面。关于前台有一点要提的就是,我是在App.vue的导航条处设置的搜索栏,这里用户点击确定后路由会渲染新组件SearchResult.vue,此时App会把用户输入数据发送给该子组件,具体实现如下:

                search: function(e) {
                    if(e.keyCode === 13) {
                        // 跳转到搜索结果页面,把数据发送过去
                        this.$router.push({
                            name: 'SearchResult',
                            query: {
                                str: this.searchStr
                            }
                        })
                        this.$router.go(0)
                    }
                }

    SearchResult.vue组件接收数据:”this.str = this.$route.query.str“

    上面是用了路由的query参数,我要说的问题就是,当用户第一次搜索的时候跳转很成功,但是如果在SearchResult搜索结果页面再次在搜索框输入数据之后,是必须刷新一次页面的数据才会更新,不然会完全没有反应,也就是search函数继续执行,但是str就是不更新。所以注意上面我写的this.$router.go(0),这是路由跳转函数,go(0)就表示跳转到浏览器历史纪录中的当前地址,全局路由一定要设置mode:history,否则会出错。

    下面实现的就是歌手页面,也没有什么特别的技术,就不赘述了。以上

  • 相关阅读:
    数据量过大时数据库操作的处理
    VC中回调函数的用法
    基于BindingSource的WinForm开发
    VC获取各类指针
    GetSystemMetrics()函数的用法
    samba建立个人专享网盘
    Windows 7下用Windows照片查看器打开图片速度变慢的解决方案
    这是一个模板
    QT中编译和使用OPENCV
    MFC日志(2011.4.9)
  • 原文地址:https://www.cnblogs.com/oujiamin/p/7802469.html
Copyright © 2020-2023  润新知