1.vue 目录位置:resources/js/components
PhpStorm语法设置:
1.1 在reources/js/components文件夹内新建一个QuestionFollowButton.vue文件【问题关注按钮vue组件】
将原show.blade.php中的 关注按钮部分 移入新vue组件内部:
初步样式:
执行
1 npm install & npm run watch-poll
刷新页面看到
现在只是大致样式,还不能工作,因为要用ajax请求 所以后面要去掉blade中的if can逻辑 放到vue组件中。
2.ajax
laravel 使用 prop 传递blade中的数据到vue组件中;
axios请求要注意 :then里面赋值的时候 报错property undefine 是因为在then里面 this作用域超出了,需要如下示例的代码才能起作用:
this.followable = response.data.followable;在then里面 this作用域超出了
这样会超出作用域,要修改如下:
1 mounted() {
2 let currentObj = this;
3 axios.post('/api/questions/follow', {'question': this.question, 'user': this.user})
4 .then(function (response) {
5 currentObj.followable = response.data.followable;
6 });
7 },
8 methods: {
9 follow() {
10 let currentObj = this;
11 axios.post('/api/questions/follow', {'question': this.question, 'user': this.user})
12 .then(function (response) {
13 currentObj.followable = response.data.followable;
14 }
15 );
16 },
17 }
18
QuestionFollowButton.vue文件:
1
2
3 :class="classObject"
4 @click="follow"
5 v-text="text">
6
7
8
9
10 export default {
11 props: ['question', 'user'],
12 name: "QuestionFollowButton",
13 data() {
14 return {
15 href: '',
16 followable: false,
17 }
18 },
19 computed: {
20 text() {
21 return this.followable ? "关注用户" : "取消关注";
22 },
23 classObject() {
24 return this.followable ? "btn btn-block btn-primary" : "btn btn-block btn-danger";
25 },
26 },
27 mounted() {
28 let currentObj = this;
29 axios.post('/api/questions/follow', {'question': this.question, 'user': this.user})
30 .then(function (response) {
31 currentObj.followable = response.data.followable;
32 });
33 },
34 methods: {
35 follow() {
36 let currentObj = this;
37 axios.post('/api/questions/follow', {'question': this.question, 'user': this.user})
38 .then(function (response) {
39 currentObj.followable = response.data.followable;
40 }
41 );
42 },
43 }
44 }
45
46
47
48
49
QuestionFollowButton.vue
api.php文件:
1 <?php
2
3 use Illuminate\Http\Request;
4
5 /*
6 |--------------------------------------------------------------------------
7 | API Routes
8 |--------------------------------------------------------------------------
9 |
10 | Here is where you can register API routes for your application. These
11 | routes are loaded by the RouteServiceProvider within a group which
12 | is assigned the "api" middleware group. Enjoy building your API!
13 |
14 */
15
16 Route::middleware('auth:api')->get('/user', function (Request $request) {
17 return $request->user();
18 });
19
20 Route::middleware('api')->get('/topics', function (Request $request) {
21 $query = $request->query('q');
22 return \App\Topic::query()->where('name', 'like', '%' . $query . '%')->get();
23 });
24
25 Route::middleware('api')->post('/questions/follow', 'QuestionController@followThroughApi');
26
api.php
show.blade.php文件:
1 @extends('layouts.app')
2 @section('content')
3
4
5
6 {{--问题--}}
7
8
9 {{ $question->title }}
10
11 @foreach(['success','warning','danger'] as $info)
12 @if(session()->has($info))
13
14 @endif
15 @endforeach
16
17 @can('update',$question)
18 编辑
19 @endcan
20
21 @can('destroy',$question)
22
23 @csrf
24 @method('DELETE')
25 删除
26
27 @endcan
28
29 @forelse($question->topics as $topic)
30 {{ $topic->name }}
31 @empty
32
"No Topics"
33 @endforelse
34
35
已有{{ count($question->answers) }}个回答
36
37
38
39 {!! $question->content !!}
40
41
42
43
44 {{--回答提交form--}}
45 {{--只有登录用户可以提交回答--}}
46 @if(auth()->check())
47
48
49 提交回答
50
51
52
53 @csrf
54
55
57
@error('content') {{ $message }} @enderror
58
59 提交回答
60
61
62
63 @else
64 {{--显示请登录--}}
65 登录提交答案
66 @endif
67 {{--展示答案--}}
68 @forelse($question->answers as $answer)
69
70
71
72
73 style="height: 50px" alt="{{ $answer->user->name }}">
74 {{ $answer->user->name }}
75
76 {{ $answer->updated_at }}
77
78
79
80 {!! $answer->content !!}
81
82
83
84 @empty
85
86 @endforelse
87
88
89
90
91
92
{{ $question->followers_count }}
93 关注者
94
95
96
97
98
99 user="{{ auth()->user()->id }}"user()->id }}">
100
101
102
103
104
105
106
107 @endsection
108 @section('footer-js')
109 @include('questions._footer_js')
110 @endsection
111
112
api.php
QuestionController.php文件:
1 <?php
2
3 namespace App\Http\Controllers;
4
5 use App\Http\Requests\QuestionStoreRequest;
6 use App\Models\Question;
7 use App\Repositories\QuestionRepository;
8 use App\User;
9 use Illuminate\Http\Request;
10
11 class QuestionController extends Controller
12 {
13
14 /**
15 * @var QuestionRepository
16 */
17 private $questionRepository;
18
19 public function __construct(QuestionRepository $questionRepository)
20 {
21 $this->middleware(
22 'auth',
23 [
24 'except' =>
25 [
26 'index',
27 'show',
28 'followThroughApi'
29 ]//非注册用户只能查看不能编辑添加更改删除
30 ]
31 );
32
33 $this->questionRepository = $questionRepository;
34 }
35
36
37 /** Display a listing of the resource.
38 * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
39 */
40 public function index()
41 {
42 //
43 $questions = $this->questionRepository->getQuestionPublished();
44 return view('questions.index', compact('questions'));
45 }
46
47
48 /**
49 * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
50 */
51 public function create()
52 {
53 //
54 return view('questions.create');
55 }
56
57
58 /**
59 * @param QuestionStoreRequest $request
60 * @return \Illuminate\Http\RedirectResponse
61 */
62 public function store(QuestionStoreRequest $request)//依赖注入QuestionStoreRequest实例
63 {
64 //
65 // $data = $request->validate([
66 // 'title' => 'required|min:8',
67 // 'content' => 'required|min:28',
68 // ]);
69 //存储topics
70 $topics = $this->questionRepository->normalizeTopics($request->get('topics'));
71 //初始化question要用到的数据
72 $data = $request->all();
73 $data['user_id'] = auth()->user()->id;
74
75 // $question=Question::create($data); 被下方代码取代
76 $question = $this->questionRepository->create($data);
77
78 //使用我们再question model里面添加的topics方法获得 topics关联,再使用attach方法
79 $question->topics()->attach($topics);
80
81 return redirect()->route('questions.show', $question);
82 }
83
84
85 /**
86 * @param Question $question
87 * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
88 */
89 public function show(Question $question)
90 {
91 //使用关系关联加载,with方法会将分类之下的主题一起查询出来,而且不会出现N+1影响性能的问题
92 $question->with('topics')->get();
93 //使用关系关联加载,with方法会将分类之下的回答一起查询出来,而且不会出现N+1影响性能的问题
94 $question->with('answers')->get();
95
96 return view('questions.show', compact('question'));
97 }
98
99
100 /**判断权限 返回视图
101 * @param Question $question
102 * @return \Illuminate\Contracts\View\Factory|\Illuminate\Http\RedirectResponse|\Illuminate\View\View
103 */
104 public function edit(Question $question)
105 {
106 if (auth()->user()->can('update', $question)) //判断当前用户是否有权编辑更新该question实例
107 {
108 //返回编辑视图
109 return view('questions.edit', compact('question'));
110 } else {
111 //返回警告 没有权限
112 return redirect()->back()->with('warning', '你不能编辑不属于你的问题!');
113 }
114 }
115
116
117 /** Update the specified resource in storage.
118 * @param QuestionStoreRequest $questionStoreRequest
119 * @param Question $question
120 * @return \Illuminate\Http\RedirectResponse
121 */
122 public function update(QuestionStoreRequest $questionStoreRequest, Question $question)
123 {
124 //更新前 判断下权限
125 if (!(auth()->user()->can('update', $question))) {
126 //返回警告 没有权限
127 return redirect()->back()->with('warning', '你不能编辑不属于你的问题!');
128 }
129 //取得更新的字段 使用Eloquent提供的update方法执行问题更新
130 $question->update([
131 'title' => $questionStoreRequest->get('title'),
132 'content' => $questionStoreRequest->get('content'),
133 ]);
134
135
136 //topics的操作这时候看起来有点臃肿 可以使用TopicController来管理,暂时省略
137 //存储topics
138 $topics = $this->questionRepository->normalizeTopics($questionStoreRequest->get('topics'));
139 //使用我们再question model里面添加的topics方法获得 topics关联,
140 //再使用sync方法同步tag 【删除的会被删除掉,没删除的就保留,新的就增加】
141 $question->topics()->sync($topics);
142
143 //更新完成,跳转回去
144 return redirect()->back();
145 }
146
147
148 /**Remove the specified resource from storage.
149 * @param Question $question
150 * @return \Illuminate\Http\RedirectResponse
151 * @throws \Exception
152 */
153 public function destroy(Question $question)
154 {
155 //
156 if (auth()->user()->can('destroy', $question)) {
157 $question->delete();
158 return redirect()->route('questions.index')->with('success', "删除成功!");
159 }
160 return redirect()->back()->with('danger', "你不能删除不属于你的问题!");
161 }
162
163
164 public function follow(Question $question)
165 {
166 if (auth()->user()->can('follow', $question)) //通过QuestionPolicy的follow方法判断用户是否可以关注问题
167 {
168 $message = "关注";
169 } else {
170 $message = "取关";
171 }
172 //同步记录
173 auth()->user()->followQuestions()->toggle($question);
174 $question->followers_count = $question->followUsers()->count();
175 $question->save();
176 return redirect()->back()->with('success', $message . '成功!');
177 }
178
179 public function followThroughApi(Request $request)
180 {
181 $user = User::find($request->get('user'));
182 $question = Question::find($request->get('question'));
183
184 if ($user->can('follow', $question)) {
185 $followable = false;
186 } else {
187 $followable = true;
188 }
189 //同步记录
190 $user->followQuestions()->toggle($question->id);
191 $question->followers_count = $question->followUsers()->count();
192 $question->update();
193 return response()->json([
194 'followable' => $followable,
195 ]);
196 }
197 }
198
QuestionController.php
QuestionPlolicy.php文件:
1 <?php
2
3 namespace App\Policies;
4
5 use App\Models\Question;
6 use App\User;
7 use Illuminate\Auth\Access\HandlesAuthorization;
8
9 class QuestionPolicy
10 {
11 use HandlesAuthorization;
12
13 /**
14 * Create a new policy instance.
15 *
16 * @return void
17 */
18 public function __construct()
19 {
20 //
21
22 }
23
24
25 /**
26 * 判断用户是否有权编辑更新问题
27 * @param User $user
28 * @param Question $question
29 * @return bool
30 */
31 public function update(User $user, Question $question)
32 {
33 return $user->id === $question->user_id;
34 }
35
36
37 /**
38 * 判断用户是否有权删除问题
39 * @param User $user
40 * @param Question $question
41 * @return bool
42 */
43 public function destroy(User $user, Question $question)
44 {
45 return $user->id === $question->user_id;
46 }
47
48
49 /** 用户是否可以关注问题,未登录不行,关注了不行
50 * @param User $user
51 * @param Question $question
52 * @return bool
53 */
54 public function follow(User $user, Question $question)
55 {
56 //axiox api 需要auth:api 先不实现,注释掉
57 // if (auth()->check()) {
58 // return !$user->followQuestions->contains('id', $question->id);
59 // } else {
60 // abort(401, "请登录");
61 // }
62 return !$user->followQuestions->contains('id', $question->id);
63 }
64 }
65
QuestionController.php