37. Vue 回复添加组件
- 本系列文章为
laracasts.com
的系列视频教程——Let's Build A Forum with Laravel and TDD 的学习笔记。若喜欢该系列视频,可去该网站订阅后下载该系列视频, 支持正版 ;- 视频源码地址:github.com/laracasts/Lets-Build-a-...;
- 本项目为一个 forum(论坛)项目,与本站的第二本实战教程 《Laravel 教程 - Web 开发实战进阶》 类似,可互相参照。
本节说明
- 对应视频教程第 37 小节:A New Reply Vue Component
本节内容
本节我们将添加回复的区域抽取成 Vue 组件。首先新建组件:
forum\resources\assets\js\components\NewReply.vue
<template>
<div>
<div class="form-group">
<textarea name="body"
id="body"
class="form-control"
placeholder="说点什么吧..."
rows="5"
required
v-model="body"></textarea>
</div>
<button type="submit" class="btn btn-default" @click="addReply">
提交
</button>
<!--<p class="text-center">请先<a href="{{ route('login') }}">登录</a>,然后再发表回复 </p>-->
</div>
</template>
<script>
export default {
data() {
return {
body:'',
endpoint:'/threads/atque/5/replies'
};
},
methods: {
addReply() {
axios.post(this.endpoint, { body:this.body })
.then(({data}) => {
this.body = '';
flash('Your reply has been posted.');
this.$emit('created',data);
});
}
}
}
</script>
注意:以上的
post
提交路径为endpoint:'/threads/atque/5/replies
,为了方便快速完成功能而暂时写死,稍后进行完善。你的路径与以上所示路径会有不同。
注释掉视图相应区域:
forum\resources\views\threads\show.blade.php
.
.
<replies :data="{{ $thread->replies }}" @removed="repliesCount--"></replies>
{{--@foreach ($replies as $reply)--}}
{{--@include('threads.reply')--}}
{{--@endforeach--}}
{{--{{ $replies->links() }}--}}
{{--@if (auth()->check())--}}
{{--<form method="post" action="{{ $thread->path() . '/replies' }}">--}}
{{--{{ csrf_field() }}--}}
{{--<div class="form-group">--}}
{{--<textarea name="body" id="body" class="form-control" placeholder="说点什么吧..."rows="5"></textarea>--}}
{{--</div>--}}
{{--<button type="submit" class="btn btn-default">提交</button>--}}
{{--</form>--}}
{{--@else--}}
{{--<p class="text-center">请先<a href="{{ route('login') }}">登录</a>,然后再发表回复 </p>--}}
{{--@endif--}}
</div>
.
.
接下来在Replies.vue
组件中引入:
forum\resources\assets\js\components\Replies.vue
<template>
<div>
<div v-for="(reply ,index) in items">
<reply :data="reply" @deleted="remove(index)"></reply>
</div>
<new-reply @created="add"></new-reply>
</div>
</template>
<script>
import Reply from './Reply';
import NewReply from './NewReply';
export default {
props: ['data'],
components: { Reply,NewReply },
data() {
return {
items:this.data
}
},
methods: {
add(reply){
this.items.push(reply);
},
remove(index) {
this.items.splice(index,1);
this.$emit('removed');
flash('Reply has been deleted!');
}
}
}
</script>
我们点击NewReply.vue
组件的提交按钮,触发addReply
函数,然后我们提交回复,并触发created
;Replies.vue
父组件监听到created
事件,触发add
函数,并将新的回复添加到回复区域,重新渲染回复区域显示所有回复。但是要注意的是,我们发送的是Ajax
请求,所以我们要修改一下控制器:
forum\app\Http\Controllers\RepliesController.php
.
.
public function store($channelId,Thread $thread)
{
$this->validate(request(),['body' => 'required']);
$reply = $thread->addReply([
'body' => request('body'),
'user_id' => auth()->id(),
]);
if(request()->expectsJson()){
return $reply->load('owner');
}
return back()->with('flash','Your reply has been left.');
}
.
.
注意:我们预加载了
owner
:$reply->load('owner')
,因为我们的回复显示组件会使用到。
最后,我们修改一下addReply
方法:
forum\app\Thread.php
.
.
public function addReply($reply)
{
return $this->replies()->create($reply);
}
.
.
我们来测试一下:
注意一点,我们返回了owner
,但是看一下owner
有哪些信息:
我们不想返回email
,进行处理:
forum\app\User.php
.
.
protected $hidden = [
'password', 'remember_token','email'
];
.
.
接下来我们处理无权限用户提交回复的问题。现在我们的页面,未登录用户也能看到提交回复区域,我们需要进行修复:
forum\resources\assets\js\components\NewReply.vue
<template>
<div>
<div v-if="signedIn">
<div class="form-group">
<textarea name="body"
id="body"
class="form-control"
placeholder="说点什么吧..."
rows="5"
required
v-model="body"></textarea>
</div>
<button type="submit" class="btn btn-default" @click="addReply">
提交
</button>
</div>
<p class="text-center" v-else>
请先<a href="/login">登录</a>,然后再发表回复
</p>
</div>
</template>
<script>
export default {
data() {
return {
body:'',
endpoint:'/threads/atque/5/replies'
};
},
computed:{
signedIn(){
return window.App.signIn;
}
},
methods: {
addReply() {
axios.post(this.endpoint, { body:this.body })
.then(({data}) => {
this.body = '';
flash('Your reply has been posted.');
this.$emit('created',data);
});
}
}
}
</script>
如果用户signedIn
,才显示回复区域:
不要忘记,在之前为了方便,我们的uri
是写死的,我们要进行修复:
forum\resources\assets\js\components\Replies.vue
<template>
<div>
.
.
<new-reply :endpoint="endpoint" @created="add"></new-reply>
</div>
</template>
<script>
.
.
data() {
return {
items:this.data,
endpoint: location.pathname+'/replies'
}
},
.
.
</script>
forum\resources\assets\js\components\NewReply.vue
.
.
<script>
export default {
props :['endpoint'],
data() {
return {
body:''
};
},
.
.
</script>
我们利用location.pathname+'/replies'
拼接成我们需要的uri
,并且在NewReply.vue
组件的props
属性中获取到uri
。我们还剩下最后一件事情要做,那就是我们新增回复,回复数也应该加 1 。这很好解决,仿照我们删除回复即可:
forum\resources\views\threads\show.blade.php
.
.
<replies :data="{{ $thread->replies }}"
@added="repliesCount++"
@removed="repliesCount--"></replies>
.
.
forum\resources\assets\js\components\Replies.vue
<script>
.
.
methods: {
add(reply){
this.items.push(reply);
this.$emit('added');
},
.
.
</script>
我们最后来测试一下: