Laravel Vuejs 实战:开发知乎 (42-44)用户头像

1.组件式上传头像vue组件:

安装扩展包:vue-image-crop-upload 或者 Vue Avatar Cropper我用的这个,暂时弃坑,需要加一个csrftoken

执行:

  1 npm i vue-avatar-cropper
  1 npm install & npm run watch-poll

使用vue-image-crop-upload

执行:

  1 npm install vue-image-crop-upload
  1 npm run watch-poll

2.路由:

添加:

  1 #region
  2 //访问用户详细页面
  3 
  4 Route::get('/avatar', 'UserController@avatar')->name('users.avatar');
  5 
  6 #endregion
  7 

3.执行:

  1 php artisan make:controller UserController

增加UserContoller.php,代码如下:

  1 <?php
  2 
  3 namespace App\Http\Controllers;
  4 
  5 use Illuminate\Http\Request;
  6 
  7 class UserController extends Controller
  8 {
  9     //
 10 
 11     /** 返回用户avatar页面视图
 12      * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
 13      */
 14     public function avatar()
 15     {
 16         return view('users._avatar');
 17     }
 18 
 19 
 20 }
 21 
 22 
UserController.php

4.增加视图文件:\views\users\_avatar.blade.php:

  1 @extends('layouts.app')
  2 
  3 @section('content')
  4 
  5     <div class="container">
  6         <div class="row">
  7             <div class="col-md-8 col-md-offset-2">
  8                 <div class="card">
  9                     <div class="card-header">
 10                         更换头像
 11                     </div>
 12                     <div class="card-body">
 13                         <avatar avatar="{{ auth()->user()->avatar }}"></avatar>
 14                     </div>
 15                 </div>
 16             </div>
 17         </div>
 18     </div>
 19 
 20 @endsection
 21 
 22 
_avatar.blade.php

5.vue组件:

执行:

  1 npm install babel-polyfill
安装babel-polyfill

代码:

  1 <template>
  2     <div>
  3         <a class="btn btn-success" @click="toggleShow">设置头像</a>
  4         <my-upload field="img"
  5                    @crop-success="cropSuccess"
  6                    @crop-upload-success="cropUploadSuccess"
  7                    @crop-upload-fail="cropUploadFail"
  8                    v-model="show"
  9                    :width="300"
 10                    :height="300"
 11                    url="/upload"
 12                    :params="params"
 13                    :headers="headers"
 14                    img-format="png"></my-upload>
 15         <img :src="imgDataUrl">
 16     </div>
 17 </template>
 18 
 19 <script>
 20     import 'babel-polyfill'; // es6 shim
 21     import myUpload from 'vue-image-crop-upload';
 22 
 23     export default {
 24         props: ['avatar'],
 25         name: "Avatar",
 26         data: function () {
 27             return {
 28                 show: false,
 29                 params: {
 30                     token: '123456798',
 31                     name: 'avatar'
 32                 },
 33                 headers: {
 34                     smail: '*_~'
 35                 },
 36                 imgDataUrl: this.avatar // the datebase64 url of created image
 37             }
 38         },
 39         components: {
 40             'my-upload': myUpload
 41         },
 42         methods: {
 43             toggleShow() {
 44                 this.show = !this.show;
 45             },
 46             /**
 47              * crop success
 48              *
 49              * [param] imgDataUrl
 50              * [param] field
 51              */
 52             cropSuccess(imgDataUrl, field) {
 53                 console.log('-------- 剪截成功 --------');
 54                 this.imgDataUrl = imgDataUrl;
 55             },
 56             /**
 57              * upload success
 58              *
 59              * [param] jsonData  server api return data, already json encode
 60              * [param] field
 61              */
 62             cropUploadSuccess(jsonData, field) {
 63                 console.log('-------- 上传成功 --------');
 64                 console.log(jsonData);
 65                 console.log('field: ' + field);
 66             },
 67             /**
 68              * upload fail
 69              *
 70              * [param] status    server api return error status, like 500
 71              * [param] field
 72              */
 73             cropUploadFail(status, field) {
 74                 console.log('-------- 上传失败 --------');
 75                 console.log(status);
 76                 console.log('field: ' + field);
 77             }
 78         }
 79 
 80     }
 81 </script>
 82 
 83 <style scoped>
 84 
 85 </style>
 86 
 87 
Avatar.vue 还未配置完

6.app.js:

  1 /**
  2  * First we will load all of this project's JavaScript dependencies which
  3  * includes Vue and other libraries. It is a great starting point when
  4  * building robust, powerful web applications using Vue and Laravel.
  5  */
  6 
  7 require('./bootstrap');
  8 require('../../vendor/select2/select2/dist/js/select2.js');
  9 // 将views/vendor/ueditor/assets.blade.php中的引用换到本处
 10 require('../../public/vendor/ueditor/ueditor.config.js');
 11 require('../../public/vendor/ueditor/ueditor.all.js');
 12 
 13 window.Vue = require('vue');
 14 
 15 /**
 16  * The following block of code may be used to automatically register your
 17  * Vue components. It will recursively scan this directory for the Vue
 18  * components and automatically register them with their "basename".
 19  *
 20  * Eg. ./components/ExampleComponent.vue -> <example-component></example-component>
 21  */
 22 
 23 // const files = require.context('./', true, /\.vue$/i)
 24 // files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default))
 25 
 26 // Vue.component('example-component', require('./components/ExampleComponent.vue').default);
 27 Vue.component('question-follow-button', require('./components/QuestionFollowButton').default);
 28 Vue.component('user-follow-button', require('./components/UserFollowButton').default);
 29 Vue.component('user-vote-button', require('./components/UserVoteButton').default);
 30 Vue.component('send-message', require('./components/SendMessage').default);
 31 Vue.component('comments', require('./components/Comments').default);
 32 Vue.component('avatar', require('./components/Avatar').default);
 33 /**
 34  * Next, we will create a fresh Vue application instance and attach it to
 35  * the page. Then, you may begin adding components to this application
 36  * or customize the JavaScript scaffolding to fit your unique needs.
 37  */
 38 
 39 const app = new Vue({
 40     el: '#app',
 41 });
 42 
 43 
app.js


7.配置图片上传到服务器本地:

web.php添加:

  1 <?php
  2 
  3 /*
  4 |--------------------------------------------------------------------------
  5 | Web Routes
  6 |--------------------------------------------------------------------------
  7 |
  8 | Here is where you can register web routes for your application. These
  9 | routes are loaded by the RouteServiceProvider within a group which
 10 | contains the "web" middleware group. Now create something great!
 11 |
 12 */
 13 
 14 Route::get('/', function () {
 15     return view('welcome');
 16 });
 17 
 18 Auth::routes(['verify' => true]);
 19 
 20 Route::get('/home', 'HomeController@index')->name('home');
 21 
 22 Route::resource('questions', 'QuestionController');
 23 
 24 
 25 #region 回答路由CRUD
 26 
 27 //查看回答 以及 回答的form 都是在questions详细内容页面
 28 
 29 //提交回答
 30 Route::post('questions/{question}/answers', 'AnswerController@store')->name('answers.store');
 31 
 32 //更新回答
 33 
 34 
 35 //删除回答
 36 
 37 
 38 #endregion
 39 
 40 
 41 #region
 42 //用户关注 取消关注问题
 43 Route::get('questions/{question}/follow', 'QuestionController@follow')->name('questions.follow');
 44 #endregion
 45 
 46 
 47 #region
 48 
 49 //用户通知消息路由
 50 Route::get('/notifications', 'NotificationController@index')->name('notification.index');
 51 #endregion
 52 
 53 #region
 54 //用户查看短消息
 55 Route::get('/inbox', 'InboxController@index')->name('inbox.index');
 56 
 57 //展示用户间私信对话具体内容页
 58 Route::get('/inbox/{userId}', 'InboxController@show')->name('inbox.show');
 59 
 60 //用户回信息
 61 Route::post('/inbox/{userId}/send', 'InboxController@store')->name('inbox.store');
 62 #endregion
 63 
 64 
 65 #region
 66 //访问用户详细页面
 67 
 68 Route::get('/avatar', 'UserController@avatar')->name('users.avatar');
 69 
 70 Route::post('/avatar/upload', 'UserController@avatarStore');
 71 
 72 #endregion
 73 
 74 
 75 
 76 
web.php

UserContoller.php增加代码如下:

  1 <?php
  2 
  3 namespace App\Http\Controllers;
  4 
  5 use Illuminate\Http\Request;
  6 
  7 class UserController extends Controller
  8 {
  9     //
 10     public function __construct()
 11     {
 12         $this->middleware('auth');
 13     }
 14 
 15 
 16     /** 返回用户avatar页面视图
 17      * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
 18      */
 19     public function avatar()
 20     {
 21         return view('users._avatar');
 22     }
 23 
 24     public function avatarStore(Request $request)
 25     {
 26         $user = auth()->user();
 27         $file = $request->file('img');
 28         $fileName = md5(time() . $user->id) . '.' . $file->getClientOriginalExtension();
 29         $file->move('uploads/image/avatars', $fileName);
 30 
 31         $user->avatar = asset('uploads/image/avatars/' . $fileName);
 32 
 33         $user->save();
 34 
 35         return response()->json(
 36             [
 37                 'url' => $user->avatar,
 38             ]);
 39     }
 40 }
 41 
 42 
UserController.php

Vue文件修改:

注意这个token在laravel中应该是_token,否则会419未授权。

批注 2020-03-04 220629

  1 <template>
  2     <div>
  3         <a class="btn btn-success" @click="toggleShow">设置头像</a>
  4         <my-upload field="img"
  5                    @crop-success="cropSuccess"
  6                    @crop-upload-success="cropUploadSuccess"
  7                    @crop-upload-fail="cropUploadFail"
  8                    v-model="show"
  9                    :width="300"
 10                    :height="300"
 11                    url="/avatar/upload"
 12                    :params="params"
 13                    :headers="headers"
 14                    img-format="png"></my-upload>
 15         <img :src="imgDataUrl" style="width:50px">
 16     </div>
 17 </template>
 18 
 19 <script>
 20     import 'babel-polyfill'; // es6 shim
 21     import myUpload from 'vue-image-crop-upload';
 22 
 23     export default {
 24         props: ['avatar'],
 25         name: "Avatar",
 26         data: function () {
 27             return {
 28                 show: false,
 29                 params: {
 30                     _token: document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
 31                     name: 'avatar'
 32                 },
 33                 headers: {
 34                     smail: '*_~',
 35                 },
 36                 imgDataUrl: this.avatar // the datebase64 url of created image
 37             }
 38         },
 39         components: {
 40             'my-upload': myUpload
 41         },
 42         methods: {
 43             toggleShow() {
 44                 this.show = !this.show;
 45             },
 46             /**
 47              * crop success
 48              *
 49              * [param] imgDataUrl
 50              * [param] field
 51              */
 52             cropSuccess(imgDataUrl, field) {
 53                 console.log('-------- 剪截成功 --------');
 54                 this.imgDataUrl = imgDataUrl;
 55             },
 56             /**
 57              * upload success
 58              *
 59              * [param] jsonData  server api return data, already json encode
 60              * [param] field
 61              */
 62             cropUploadSuccess(jsonData, field) {
 63                 console.log('-------- 上传成功 --------');
 64                 // console.log(jsonData);
 65                 // console.log('field: ' + field);
 66                 this.toggleShow();
 67             },
 68             /**
 69              * upload fail
 70              *
 71              * [param] status    server api return error status, like 500
 72              * [param] field
 73              */
 74             cropUploadFail(status, field) {
 75                 console.log('-------- 上传失败 --------');
 76                 console.log(status);
 77                 console.log('field: ' + field);
 78             }
 79         }
 80 
 81     }
 82 </script>
 83 
 84 <style scoped>
 85 
 86 </style>
 87 
 88 
Avatar.vue


8.七牛云存储:

posted @ 2020-03-04 15:31  dzkjz  阅读(279)  评论(0编辑  收藏  举报