初始化项目
composer create-project laravel/laravel comments
创建数据库,配置.env
文件。我这里的数据库是comments
使用系统自带的验证程序。
php artisan make:auth
php artisan migrate
使用npm命令安装依赖和tailwindcss
cnpm install tailwindcss --save-dev
cnpm install
本教程涉及到的代码我都将上传至:
https://github.com/leienshu/comments
构建组件结构
先使用下面的命令来观察sass文件或者js文件的一些变动情况。
npm run watch
清除home.blade.php
文件中@section 和 @endsection 部分的内容。
对了,上面的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>
上面的代码看懂了么?我们在<script>标签里面引入CommentItem的comment属性。在评论显示的地方用v-for和:key来提取评论。
评论显示好了,但是还不能编辑,下面我们就来编辑评论。
编辑评论
因为我们的编辑功能并不是对所有人开放的,所以我们需要传递当前用户到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还不能编辑,我们继续。
我们首先在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已经实现了,我们下一篇文章继续实现增加Tailwind CSS,让界面优雅点。
Inspiring quest there. What happened after?
Thanks! https://bahastopikgosip1.blogspot.com/
Good article. I absolutely appreciate this website.
Continue the good work! http://www.99ceme.in/ref.php?ref=HONEYWII99
Simply want to say your article is as astounding.
The clearness in your post is just cool and i could assume you are an expert on this subject.
Well with your permission allow me to grab your RSS feed to keep up to date with forthcoming post.
Thanks a million and please keep up the rewarding
work. http://dominoqiu.link/ref.php?ref=DOMINO_QIU
Hi there! I’m at work browsing your blog from my new iphone!
Just wanted to say I love reading your blog and look forward to
all your posts! Keep up the excellent work!
Wow that was unusual. I just wrote an extremely long comment but after
I clicked submit my comment didn’t show up. Grrrr…
well I’m not writing all that over again. Regardless, just wanted
to say great blog!
Greetings! I’ve been following your web site for a long time now and finally
got the bravery to go ahead and give you a shout out from Porter Texas!
Just wanted to mention keep up the fantastic work!
I’ve been surfing online more than three hours today, yet I never found any interesting article like yours.
It is pretty worth enough for me. In my view, if all web owners and bloggers made good content as you did, the web will be much more useful than ever before.
This is a topic that is near to my heart… Many thanks! Where are your contact details though?
http://samsung.com
Thank you for the auspicious writeup. It in fact was a amusement account it.
Look advanced to far added agreeable from
you! By the way, how can we communicate? http://Backstreetsofhickory.com