使用 Vue.js、Laravel 构建评论系统-(一)
初始化项目
composer create-project laravel/laravel comments
创建数据库,配置.env
文件。我这里的数据库是comments
使用系统自带的验证程序。
php artisan make:auth
php artisan migrate
使用npm命令安装依赖
cnpm install
本教程涉及到的代码我都将上传至:
https://github.com/leienshu/comments
构建组件结构
先使用下面的命令来观察sass文件或者js文件的一些变动情况。
npm run watch
清除home.blade.php
文件中@section 和 @endsection 部分的内容。
home.blade.php
对了,上面的Laravel标题在env文件中可以改成Comments Demo。
好了,现在我们进入 resources/js/components 目录,新建一个新的Vue文件,名字叫:CommentsManager.vue ,具体内容如下:
<template>
<div>
<h1>Hello World</h1>
</div>
</template>
<script>
export default {
data: function() {
return {
}
},
}
</script>
在 app.js 文件中注册上面新建的 vue 文件。把之前的example-component注释掉。
Vue.component('comments-manager', require('./components/CommentsManager.vue').default);
在 home.blade.php 文件的section部分添加下面的模板。
<comments-manager></comments-manager>
成功引入组件
用户界面有点丑,不过我们继续干吧。
显示评论
在CommentsManager的data属性里,我们增加一些评论数据。如下:
return {
comments: [
{
id: 1,
body: "咋整的呢?",
edited: false,
created_at: new Date().toLocaleString(),
author: {
id: 1,
name: '雷经纬',
}
}
]
}
现在我们就有了一些数据可以使用,我们可以开始在页面上显示它。但是,现在虽然可以将所有逻辑保存在CommentsManager组件中,但我们最终必须编写一些奇怪的方法来解析每个注释的详细信息。所以,我们最好为每个评论制作另一个组件。
在 comments-manager.vue 相同目录下,再新建一个 CommentItem.vue 文件。
<template>
<div>
</div>
</template>
<script>
export default {
data: function() {
return {
}
},
}
</script>
现在,让我们通过一个评论属性,包含所有评论的数据,然后将其添加到模板中。
<template>
<div>
<div>
<p>{{comment.body}}</p>
</div>
<div>
<p>{{comment.author.name}} <span>--</span>{{ comment.created_at}}</p>
</div>
</div>
</template>
<script>
export default {
props: {
comment: {
required: true,
type: Object,
}
},
data: function() {
return {
}
},
}
</script>
现在进入 CommentsManager.vue 文件来注册CommentItem。
<template>
<div>
<div>
<comment v-for="comment in comments"
:key="comment.id"
:comment="comment">
</comment>
</div>
</div>
</template>
<script>
import comment from './CommentItem'
export default {
components: {
comment
},
data: function() {
return {
comments: [
{
id: 1,
body: "咋整的呢?",
edited: false,
created_at: new Date().toLocaleString(),
author: {
id: 1,
name: '雷经纬',
}
}]
}
},
}
</script>
上面的代码看懂了么?我们在
显示评论
评论显示好了,但是还不能编辑,下面我们就来编辑评论。
编辑评论
因为我们的编辑功能并不是对所有人开放的,所以我们需要传递当前用户到CommentItem里。
为此,我们需要为我们的两个组件添加一个用户属性,然后对经过身份验证的用户添加传递。我们可以这样添加那个属性:
//CommentsManager
<comment v-for="comment in comments"
:key="comment.id"
:user="user"
:comment="comment">
</comment>
...
props: {
user: {
required: true,
type: Object,
}
},
//CommentItem
props: {
user: {
required: true,
type: Object,
},
comment: {
required: true,
type: Object,
}
},
//home.blade.php
<comments-manager :user="{{ auth()->user() }}"></comments-manager>
在CommentItem中添加一个computed属性来判断当前用户是否可以编辑评论。
computed: {
editable() {
return this.user.id === this.comment.author.id;
}
}
我们再给评论添加一个Edit按钮。
<div>
<p>{{comment.body}}</p>
<button v-if="editable">Edit</button>
</div>
上面的v-if可以确保只有当前用户才能点击这个Edit按钮。然后,我们再在CommentsManeger里面的comments里面添加一个对象。
comments: [
{
id: 1,
body: "咋整的呢?",
edited: false,
created_at: new Date().toLocaleString(),
author: {
id: 1,
name: '雷经纬',
}
},
{
id: 2,
body: "这样整的啊?",
edited: false,
created_at: new Date().toLocaleString(),
author: {
id: 2,
name: '王者归来',
}
},
]
出来的效果如下图:
当前用户显示Edit按钮
怎么样,现在的Edit还不能编辑,我们继续。
我们首先在CommentItem的组件数据中添加一个state属性,这样我们就可以跟踪编辑的时间。我们还要添加一个updatedComment属性,用来跟踪我们做的更改。
data: function() {
return {
state: 'default',
data:{
body:this.comment.body,
}
}
},
因为这里的state比较简单,我就用了字符串类型,其实也可以用布尔类型。
使用comment.body中的值初始化data.body,这样就可以让我们用正确的初始数据填充编辑表单。
绑定一个点击事件,将state设置为editing。
<button v-if="editable" @click="state = 'editing'">Edit</button>
接下来,让我们添加我们的编辑表单。
<template>
<div>
<div v-show="state === 'default'">
<div>
<p>{{comment.body}}</p>
<button v-if="editable" @click="state = 'editing'">Edit</button>
</div>
<div>
<p>{{comment.author.name}} <span>--</span>{{ comment.created_at}}</p>
</div>
</div>
<div v-show="state === 'editing'">
<div>
<h3>Update Comment</h3>
</div>
<textarea v-model="data.body"
placeholder="Update comment"
class="border">
</textarea>
<div>
<button>Update</button>
<button>Cancel</button>
</div>
</div>
</div>
</template>
上面用两个div来对应state的变化,我们再添加一个resetEdit的方法,用来重置data.body和state。
//Template
<button @click="resetEdit">Cancel</button>
...
//Vue Instance
methods: {
resetEdit() {
this.state = 'default';
this.data.body = this.comment.body;
}
}
继续添加一个saveEdit()的方法。
在这里,我们有几个选项可以将我们的更改返回到评论所在的父组件。我们可以直接使用 $parent.comments 去直接访问,也可以改变我们的 comment 属性。
但这些并不是最佳选择,因为它们和我们的组件结合过于紧密。不过,这样用也不是不行。不过,我建议我们还是使用event去搞。
在saveEdit()方法中,我们把state的设置回给它的默认值,并且我们这时候将修改评论这个事件传递过去。这样在CommentsManager我们将有一个updateComment方法,当我们的事件触发时就会调用它。
//CommentItem
//Template
<button @click="saveEdit">Update</button>
//Script
saveEdit() {
this.state = 'default';
this.$emit('comment-updated', {
'id': this.comment.id,
'body': this.data.body,
});
}
//CommentsManager
//Template
<comment v-for="comment in comments"
:key="comment.id"
:user="user"
:comment="comment"
@comment-updated="updateComment($event)">
</comment>
//Script
methods: {
updateComment($event) {
let index = this.comments.findIndex((element) => {
return element.id === $event.id;
});
this.comments[index].body = $event.body;
}
}
再次打开浏览器,你就可以编辑评论了。
删除评论
跟上面的更新评论一样,我们增加一个按钮和事件就行了,具体代码如下:
//CommentItem
//Template
<div>
<button @click="saveEdit">Update</button>
<button @click="resetEdit">Cancel</button>
<button @click="deleteComment">Delete</button>
</div>
//Script
deleteComment() {
this.$emit('comment-deleted', {
'id': this.comment.id,
});
}
//Comments Manager
//Template
<comment v-for="comment in comments"
:key="comment.id"
:user="user"
:comment="comment"
@comment-updated="updateComment($event)"
@comment-deleted="deleteComment($event)">
</comment>
//Script
deleteComment($event) {
let index = this.comments.findIndex((element) => {
return element.id === $event.id;
});
this.comments.splice(index, 1);
}
添加评论
搞完了更新删除评论,我们继续来搞添加评论吧。
我们搞得简单点,直接在CommentsManager里面增加。
<template>
<div>
<div>
<div>
<h2>Comments</h2>
</div>
<textarea placeholder="Add a comment"
class="border">
</textarea>
<div>
<button>Save</button>
<button>Cancel</button>
</div>
</div>
<div>
<comment v-for="comment in comments"
:key="comment.id"
:user="user"
:comment="comment"
@comment-updated="updateComment($event)"
@comment-deleted="deleteComment($event)">
</comment>
</div>
</div>
</template>
为了实现添加功能,我们还需要添加一个saveComment的方法,并且添加一个data.body的属性到data,而且还要给textarea 添加一个v-model。
//template
<div>
<div>
<h2>Comments</h2>
</div>
<textarea v-model="comments.body"
placeholder="Add a comment"
class="border">
</textarea>
<div>
<button @click="saveComment">Save</button>
<button>Cancel</button>
</div>
</div>
//script
saveComment() {
let newComment = {
id: this.comments[this.comments.length - 1].id + 1,
body: this.comments.body,
edited: false,
created_at: new Date().toLocaleString(),
author: {
id: this.user.id,
name: this.user.name,
}
}
this.comments.push(newComment);
this.comments.body = '';
},
打开浏览器,你会发现添加功能有了。
添加评论
总结
好了,今天先到这里,界面有点丑陋,不过几本的CURD已经实现了,我们下一篇文章稍微增加点css让界面好看一点点吧。
本作品采用《CC 协议》,转载必须注明作者和本文链接