Laravel+Vue.js开发踩坑填坑

Laravel+Vue.js开发踩坑填坑,基于 Laravel + Vue 组件实现文件异步上传

参考链接地址:

https://laravelacademy.org/post/9677.html?page=1#comments

两年前的文章了,版本迭代更新之后很多东西改变了,这几天填坑之后顺利复现,给有需要的小伙伴看一下。建议同时参考下面两篇文章,有问题的地方我在后面会说明的

1.https://laravelacademy.org/post/21944
2.https://laravelacademy.org/post/9677.html?page=1#comments


1.安装Laravel

win+r cmd 进入命令行窗口
选择位置(我选择G盘根目录下)

laravel new test1

新建一个名字为test1的Laravel文件,等待其下载完成即可
在这里插入图片描述

2.初始化和编辑Laravel文件

在phpstorm中打开该文件,等待编制索引完成,先不急着点击右下角的npm install
在这里插入图片描述

2.1 开箱使用 Bootstrap 和 Vue 框架,需要运行如下命令安装 laravel/ui 库:

composer require laravel/ui

完成结果如下图所示
composer require laravel/ui

2.2 命令行中初始化 Bootstrap 和 Vue 组件脚手架代码:

php artisan ui bootstrap
php artisan ui vue

完成结果如下图所示
php artisan ui bootstrap
php artisan ui vue

2.3 安装依赖库

npm install

npm报错找不到的去下载node.js相关文件配置即可
安装过程较快,稍等片刻…
若出现下图所示结果:在这里插入图片描述

继续运行

npm audit fix
npm audit fix --force

在这里插入图片描述
安装完成后截图
在这里插入图片描述

2.4 更改路由配置RouteServiceProvider

这一步在Laravel 8.x版本中一定要做否则在本地路径下localhost:8000/xxxx打不开页面,找不到页面。
RouteServiceProvider具体内容可以参考下面的博文

https://blog.csdn.net/weixin_43197466/article/details/106772796

取消该处的注释
在这里插入图片描述
若无则添加代码

protected $namespace = 'App\\Http\\Controllers';

2.5 验证基础配置情况

resources/js/app.js


import Vue from "vue";

require('./bootstrap');

window.Vue = require('vue').default;

Vue.component('example-component', require('./components/ExampleComponent.vue').default);

const app = new Vue({
    el: '#app',
});

resources/js/bootstrap.js文件

window._ = require('lodash');


try {
    window.Popper = require('popper.js').default;
    window.$ = window.jQuery = require('jquery');

    require('bootstrap');
} catch (e) {}


window.axios = require('axios');

window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';


2.6 在routes/web.php文件测试路由

定义127.0.0.1:8000/test路径返回123

Route::get('test',function ()
{
    return '123';
});

基础设置配置成功
在这里插入图片描述

3.基于 Laravel + Vue 组件实现文件异步上传

3.1 定义文件上传路由

我们在 routes/web.php 中定义上传文件涉及到的路由,直接添加在web.php下即可

// 用于显式上传表单
Route::get('form', 'RequestController@formPage');
// 用于处理文件上传
Route::post('form/file_upload', 'RequestController@fileUpload');
<?php

use Illuminate\Support\Facades\Route;

// 用于显式上传表单
Route::get('form', 'RequestController@formPage');
// 用于处理文件上传
Route::post('form/file_upload', 'RequestController@fileUpload');

我们定义了一个 GET 路由 /form,用于渲染用户上传表单页面,然后定义了一个 POST 路由 /form/file_upload,用于实现文件上传逻辑。
接下来去控制器中初始化这两个方法。

3.2 初始化控制器方法

找到路径app/Http/Controllers/,新建RequestController.php并打开之,初始化路由定义中指定的控制器方法。(注意新建为php类)
在这里插入图片描述

在这里插入图片描述

(1)formPage 方法用于渲染表单视图,我们约定视图路径是 request.form
(2)fileUpload 方法,用于处理 POST 请求实现文件上传,假定前端文件输入框对应 name 属性是 picture,如果请求内容中包含该字段,则将对应文件实例打印出来(文件上传保存实现代码后面再完善):
注意引入Request中的方法

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;

class RequestController extends Controller
{
    public function formPage()
    {
        return view('request.form');
    }
    public function fileUpload(Request $request)
    {
        if ($request->hasFile('picture')) 
        {
            dd($request->file('picture'));
        }
    }
}

3.3 编写前端表单视图

接下来,就可以到前端编写视图文件了,我们将通过单独的 Vue 组件实现前端文件异步上传操作:
在view下新建文件夹request
新建php文件form.blade

在这里插入图片描述

代码如下:

<!doctype html>
<html lang="{{ app()->getLocale() }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="csrf-token" content="{{ csrf_token() }}">

        <title>表单请求</title>

        <link href="{{ asset('css/app.css')  }}" rel="stylesheet">
    </head>
    <body>
        <div id="app">
            <div class="container">
                <form>
                    <fileupload-component></fileupload-component>
                    <button type="submit" class="btn btn-primary">提交</button>
                </form>
            </div>
        </div>
        <script src="{{ asset('js/app.js') }}"></script>
    </body>
</html>

添加 CSRF Token 的逻辑
找到resources/js/bootstrap.js文件并在文件中添加之

let token = document.head.querySelector('meta[name="csrf-token"]');

if (token) {
    window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
} else {
    console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
}

结果如下:

window._ = require('lodash');

try {
    window.Popper = require('popper.js').default;
    window.$ = window.jQuery = require('jquery');
    
    require('bootstrap');
} catch (e) {}

window.axios = require('axios');

window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

let token = document.head.querySelector('meta[name="csrf-token"]');

if (token) {
    window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
} else {
    console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
}

3.4 编写文件上传 Vue 组件

完成视图模板文件的编写之后,接下来就可以编写文件上传 Vue 组件了。
在 resources/js/components 目录下新增 FileUploadComponent.vue,编写代码如下:

<style scoped>
    div.form-group {
        margin-top: 10px;
    }
</style>

<template>
    <div class="form-group">
        <label for="picture">上传一张图片</label>
        <input type="file" class="form-control-file" id="picture" ref="picture" v-on:change="uploadFile"/>
    </div>
</template>

<script>
    export default {
        methods: {
            uploadFile() {
                let formData = new FormData();
                formData.append('picture', this.$refs.picture.files[0]);
                axios.post(
                    '/form/file_upload',
                    formData,
                    {
                        headers: {
                            'Content-Type': 'multipart/form-data'
                        }
                    }
                ).then(function (response) {
                    console.log(response);
                }).catch(function (error) {
                    console.log(error);
                });
            }
        }
    }
</script>

在 resources/js/app.js 文件中将这个组件全局注册到 Vue 实例:

Vue.component('fileupload-component', require('./components/FileUploadComponent.vue').default);

结果如下:

import Vue from "vue";
require('./bootstrap');
window.Vue = require('vue').default;

Vue.component('example-component', require('./components/ExampleComponent.vue').default);
Vue.component('fileupload-component', require('./components/FileUploadComponent.vue').default);

const app = new Vue({
    el: '#app',
});

3.5 测试文件上传功能

(1)运行 npm run dev 重新编译前端资源
编译成功截图:
在这里插入图片描述
(2)测试
在这里插入图片描述

3.6 完善后端文件上传代码

完善function fileUpload方法(看3.2节)RequestController.php文件:

<?php


namespace App\Http\Controllers;
//这里看一下是哪一个Request类啊


use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;

class RequestController
{
    public function formPage()
    {
        return view('request.form');
    }

    public function fileUpload(Request $request)
    {
        if ($request->hasFile('picture')) {
            $picture = $request->file('picture');
            if (!$picture->isValid()) {
                abort(400, '无效的上传文件');
            }
            // 文件扩展名
            $extension = $picture->getClientOriginalExtension();
            // 文件名
            $fileName = $picture->getClientOriginalName();
            // 生成新的统一格式的文件名
            $newFileName = md5($fileName . time() . mt_rand(1, 10000)) . '.' . $extension;
            // 图片保存路径
            $savePath = 'images/' . $newFileName;
            // Web 访问路径
            $webPath = '/storage/' . $savePath;
            // 将文件保存到本地 storage/app/public/images 目录下,先判断同名文件是否已经存在,如果存在直接返回
            if (Storage::disk('public')->has($savePath)) {
                return response()->json(['path' => $webPath]);
            }
            // 否则执行保存操作,保存成功将访问路径返回给调用方
            if ($picture->storePubliclyAs('images', $newFileName, ['disk' => 'public'])) {
                return response()->json(['path' => $webPath]);
            }
            abort(500, '文件上传失败');
        } else {
            abort(400, '请选择要上传的文件');
        }
    }
}

如果要让上传到 storage/app/public 目录的文件可以被外部访问,还要执行以下命令:

php artisan storage:link

3.7 优化前端图片上传组件代码

FileUploadComponent.vue组件中对前端文件上传代码进行调整和优化

<template>
    <div class="form-group">
        <label for="picture">上传一张图片</label>
        <input type="file" class="form-control-file" id="picture" ref="picture" v-on:change="uploadFile"/>
        <input type="hidden" id="picture-path" value="">
        <div id="picture-preview">

        </div>
    </div>
</template>

<script>
    export default {
        methods: {
            uploadFile() {
                let formData = new FormData();
                formData.append('picture', this.$refs.picture.files[0]);
                axios.post(
                    '/form/file_upload',
                    formData,
                    {
                        headers: {
                            'Content-Type': 'multipart/form-data'
                        }
                    }
                ).then(function (response) {
                    $('#picture-path').val(response.data.path);
                    $('#picture-preview').html('<img src="' + response.data.path + '">')
                }).catch(function (error) {
                    console.log(error);
                });
            }
        }
    }
</script>

3.8 再次测试文件上传功能

同3.5 (2)
上传结果:
图片保存在本地storage/app/public/images下
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值