zoukankan      html  css  js  c++  java
  • Laravel Vuejs 实战:开发知乎 (20)使用 Vuejs 组件化

    1.vue 目录位置:resources/js/components

    批注 2020-03-01 105353

    PhpStorm语法设置:

    批注 2020-03-01 105541

    1.1 在reources/js/components文件夹内新建一个QuestionFollowButton.vue文件【问题关注按钮vue组件

    批注 2020-03-01 105857


    将原show.blade.php中的 关注按钮部分 移入新vue组件内部:

    批注 2020-03-01 111423

    初步样式:

    批注 2020-03-01 113240

    批注 2020-03-01 113221

    执行

      1 npm install & npm run watch-poll

    刷新页面看到

    批注 2020-03-01 113341

    现在只是大致样式,还不能工作,因为要用ajax请求 所以后面要去掉blade中的if can逻辑 放到vue组件中。

    2.ajax

    注意 vue在laravel中使用的时候,参考 laravel 中使用ajax和vue总结 

    但一般使用axios ,参考:

    入坑vue laravel,配置vue-router和axios手记 

    Vue axios的使用(解决laravel API跨域访问)

    通过 Axios 库构建 API 请求

    基于 Laravel + Vue 构建一个类似 Twitter 的 Web 应用

    vue laravel axios 教程 


    CRUD App with Laravel and Vue

    laravel 使用 prop 传递blade中的数据到vue组件中;

    laravel axios post 401

    401 during axios request

    API requests with axios always unauthorized with Laravel API

    axios请求要注意 :

    then里面赋值的时候 报错property undefine 是因为在then里面 this作用域超出了,需要如下示例的代码才能起作用:

    批注 2020-03-01 153409

    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 <template>
      2     <button :href="href"
      3             :class="classObject"
      4             @click="follow"
      5             v-text="text">
      6     </button>
      7 </template>
      8 
      9 <script>
     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 </script>
     46 
     47 <style scoped>
     48 
     49 </style>
    QuestionFollowButton.vue

    api.php文件:

      1 <?php
      2 
      3 use IlluminateHttpRequest;
      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 AppTopic::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     <div class="container">
      4         <div class="row">
      5             <div class="col-md-8 col-md offset-1">
      6                 {{--问题--}}
      7                 <div class="card">
      8                     <div class="card-header">
      9                         {{ $question->title }}
     10 
     11                         @foreach(['success','warning','danger'] as $info)
     12                             @if(session()->has($info))
     13                                 <div class="alert alert-{{$info}}">{{ session()->get($info) }}</div>
     14                             @endif
     15                         @endforeach
     16 
     17                         @can('update',$question)
     18                             <a href="{{ route('questions.edit',$question) }}" class="btn btn-warning">编辑</a>
     19                         @endcan
     20 
     21                         @can('destroy',$question)
     22                             <form action="{{ route('questions.destroy',$question) }}" method="post">
     23                                 @csrf
     24                                 @method('DELETE')
     25                                 <button type="submit" class="btn btn-danger">删除</button>
     26                             </form>
     27                         @endcan
     28 
     29                         @forelse($question->topics as $topic)
     30                             <button class="btn btn-secondary float-md-right m-1">{{ $topic->name }}</button>
     31                         @empty
     32                             <p class="text text-warning float-md-right"> "No Topics"</p>
     33                         @endforelse
     34 
     35                         <p class="text text-info float-md-right"> 已有{{ count($question->answers) }}个回答</p>
     36 
     37                     </div>
     38                     <div class="card-body">
     39                         {!! $question->content !!}
     40                     </div>
     41                 </div>
     42 
     43 
     44                 {{--回答提交form--}}
     45                 {{--只有登录用户可以提交回答--}}
     46                 @if(auth()->check())
     47                     <div class="card mt-2">
     48                         <div class="card-header">
     49                             提交回答
     50                         </div>
     51                         <div class="card-body">
     52                             <form action="{{ route('answers.store',$question) }}" method="post">
     53                             @csrf
     54                             <!-- 回答编辑器容器 -->
     55                                 <script id="container" name="content" type="text/plain"
     56                                         style=" 100%;height: 200px">{!! old('content') !!}</script>
     57                                 <p class="text text-danger"> @error('content') {{ $message }} @enderror </p>
     58                                 <!--提交按钮-->
     59                                 <button type="submit" class="btn btn-primary float-md-right mt-2">提交回答</button>
     60                             </form>
     61                         </div>
     62                     </div>
     63                 @else
     64                     {{--显示请登录--}}
     65                     <a href="{{ route('login') }}" class="btn btn-success btn-block mt-4">登录提交答案</a>
     66                 @endif
     67                 {{--展示答案--}}
     68                 @forelse($question->answers as $answer)
     69                     <div class="card mt-4">
     70                         <div class="card-header">
     71                             <div class="float-left">
     72                                 <img src="{{ $answer->user->avatar }}" class="img-thumbnail imgWrap"
     73                                      style="height: 50px" alt="{{ $answer->user->name }}">
     74                                 <span class="text text-info">{{ $answer->user->name }}</span>
     75                             </div>
     76                             <span class="float-right text text-info m-auto">{{ $answer->updated_at }}</span>
     77                         </div>
     78 
     79                         <div class="card-body">
     80                             {!!  $answer->content  !!}
     81                         </div>
     82                     </div>
     83 
     84                 @empty
     85 
     86                 @endforelse
     87             </div>
     88 
     89             <div class="col-md-3">
     90                 <div class="card">
     91                     <div class="card-header">
     92                         <h2> {{ $question->followers_count }}</h2>
     93                         <span>关注者</span>
     94                     </div>
     95 
     96                     <div class="card-body">
     97                         <div id="app">
     98                             <question-follow-button question="{{$question->id}}"
     99                                                     user="{{ auth()->user()->id }}"user()->id }}">
    100                             </question-follow-button>
    101                         </div>
    102                     </div>
    103                 </div>
    104             </div>
    105         </div>
    106     </div>
    107 @endsection
    108 @section('footer-js')
    109     @include('questions._footer_js')
    110 @endsection
    111 
    112 
    api.php

    QuestionController.php文件:

      1 <?php
      2 
      3 namespace AppHttpControllers;
      4 
      5 use AppHttpRequestsQuestionStoreRequest;
      6 use AppModelsQuestion;
      7 use AppRepositoriesQuestionRepository;
      8 use AppUser;
      9 use IlluminateHttpRequest;
     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 IlluminateContractsViewFactory|IlluminateViewView
     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 IlluminateContractsViewFactory|IlluminateViewView
     50      */
     51     public function create()
     52     {
     53         //
     54         return view('questions.create');
     55     }
     56 
     57 
     58     /**
     59      * @param QuestionStoreRequest $request
     60      * @return IlluminateHttpRedirectResponse
     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 IlluminateContractsViewFactory|IlluminateViewView
     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 IlluminateContractsViewFactory|IlluminateHttpRedirectResponse|IlluminateViewView
    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 IlluminateHttpRedirectResponse
    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 IlluminateHttpRedirectResponse
    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 AppPolicies;
      4 
      5 use AppModelsQuestion;
      6 use AppUser;
      7 use IlluminateAuthAccessHandlesAuthorization;
      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
  • 相关阅读:
    Linux中find命令用法全汇总,看完就没有不会用的!
    ubuntu16.04 通过命令,修改屏幕分辨率
    Linux下如何查看哪些进程占用的CPU内存资源最多
    shell脚本 在后台执行de 命令 >> 文件 2>&1 将标准输出与错误输出共同写入到文件中(追加到原有内容的后面)
    ef linq 访问视图返回结果重复
    asp.net core web 本地iis开发
    jQuery控制TR显示隐藏
    mvc EF 从数据库更新实体,添加视图实体时添加不上的问题
    无法确定依赖操作的有效顺序。由于外键约束、模型要求或存储生成的值,因此可能存在依赖关系
    还原差异备份——因为没有文件可用于前滚
  • 原文地址:https://www.cnblogs.com/dzkjz/p/12390008.html
Copyright ? 2011-2022 开发猿


http://www.vxiaotou.com