Laravel 和 Vue.js 是 Web 开发中常用的两个强大的框架。 Laravel 提供了全面的后端解决方案,而 Vue.js 提供了灵活高效的方式来构建交互式前端组件。尽管 Laravel 为动态界面提供了 Inertia.js 和 Livewire 等替代选项,一般情况下的项目,都是采用前后端分离开发,laravel负责后端接口,vue.js负责前端页面,但在某些情况下,特别是对于全栈开发者,开发人员更喜欢将 Vue.js 直接集成到他们的 Laravel 项目中。本文讲解具体集成方法。
先决条件:开始之前,请确保您具备以下条件:
- Laravel 框架的基础知识
- 熟悉 Vue3 基础知识
安装Laravel
本文不讲解php和composer的安装和配置了,这两个是最基本的,如果这两个都不会安装,您也不用看本文了,我们直接通过composer来安装laravel项目。请在终端中运行以下命令:
composer create-project laravel/laravel:^9.0 laravel9-vue3 cd laravel9-vue3 php artisan serve
当可以访问到http://127.0.0.1:8000/页面时即安装成功
安装 Laravel Breeze
Laravel Breeze 是一个轻量级的脚手架包,它为 Laravel 应用程序中的身份验证提供了最小的设置。要安装 Laravel Breeze,请在终端中运行以下命令:
composer require laravel/breeze --dev
安装后,通过运行以下命令生成身份验证脚手架:
php artisan breeze:install
安装数据库并做好配置
我们可以通过宝塔或者phpmysqladmin数据库管理工具创建数据库。安装好数据库之后,在项目根目录配置好.env文件的数据库信息
运行数据库迁移
现在,运行数据库迁移来设置身份验证和用户管理所需的表。在终端中执行以下命令:
php artisan migrate
安装依赖项并构建静态资源
要安装必要的前端依赖项并构建资源,请运行以下命令:
npm install npm run dev
启动本地Laravel服务
前面的npm run dev不要终止,开启另一个命令行窗口,要在本地启动Laravel服务,请运行以下命令:
php artisan serve
现在就可以使用提供的 URL 在 Web 浏览器中访问项目了。
安装Vue.js和Vue Loader
为了增强使用 Vue.js 组件时的开发体验,我们将安装 Vue Loader。 Vue Loader 是 Webpack 加载器,可以编写单文件 Vue 组件。它将 HTML、CSS 和 JavaScript 组合在一个文件中,从而简化了组件结构。
要安装 Vue Loader,请运行以下命令:npm install vue@next vue-loader@next
安装vite的vue.js插件
Vite 是下一代前端构建工具,Laravel 提供了一个插件将其与您的 Laravel 应用程序集成。运行以下命令安装 Vite 的 Vue.js 插件:
npm i @vitejs/plugin-vue
更新Vite配置
要配置 Vite,我们打开项目根目录下的 vite.config.js 文件,并使用以下代码更新它:
import { defineConfig } from 'vite'; import laravel from 'laravel-vite-plugin'; import vue from '@vitejs/plugin-vue';
export default defineConfig({
plugins: [
vue({
template: {
transformAssetUrls: {
base: null,
includeAbsolute: false,
},
},
}),
laravel({
input: [
'resources/css/app.css',
'resources/js/app.js',
],
refresh: true,
}),
],
resolve: {
alias: {
'@': '/resources/js',
'vue': 'vue/dist/vue.esm-bundler.js'
},
},
});
# **编写vue页面**
修改resources/js目录下的app.js
```php
import './bootstrap';
import { createApp } from 'vue';
import ComponentA from './components/ComponentA.vue';
import App from './App.vue';
const app = createApp(App);
app.component('ComponentA', ComponentA);
app.mount("#app");
app.js同目录下新建App.vue,内容如下
<template>
<div>
<h1>Laravel9+Vue3快速开发</h1>
<component-a></component-a>
</div>
</template>
<script>
import ComponentA from './components/ComponentA.vue'
export default {
components:{
ComponentA
}
}
</script>
<style>
</style>
在 resources/js 目录中创建一个名为“components”的新文件夹。在“components”文件夹中,创建一个 Vue.js 组件文件,例如 ComponentA.vue ,并定义组件的模板和逻辑。例如:
<template>
<h1>Laravel9 + Vue3.0独立开发者快速开发</h1>
</template>
修改Blade模板
为了使 Vue.js 组件与 Laravel 的 Blade 模板引擎配合使用,我们需要对 Blade 文件进行一些修改。由于laravel默认首页为,我们打开 welcome.blade.php 。修改一下内容,注意要在html头部加入@vite(['resources/css/app.css', 'resources/js/app.js']),修改后内容大致如下
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Laravel</title>
<!-- Fonts -->
<link href="https://fonts.bunny.net/css2?family=Nunito:wght@400;600;700&display=swap" rel="stylesheet">
<!-- Styles -->
<style>
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}a{background-color:transparent}[hidden]{display:none}html{font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5}*,:after,:before{box-sizing:border-box;border:0 solid #e2e8f0}a{color:inherit;text-decoration:inherit}svg,video{display:block;vertical-align:middle}video{max-width:100%;height:auto}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity))}.bg-gray-100{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity))}.border-gray-200{--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity))}.border-t{border-top-width:1px}.flex{display:flex}.grid{display:grid}.hidden{display:none}.items-center{align-items:center}.justify-center{justify-content:center}.font-semibold{font-weight:600}.h-5{height:1.25rem}.h-8{height:2rem}.h-16{height:4rem}.text-sm{font-size:.875rem}.text-lg{font-size:1.125rem}.leading-7{line-height:1.75rem}.mx-auto{margin-left:auto;margin-right:auto}.ml-1{margin-left:.25rem}.mt-2{margin-top:.5rem}.mr-2{margin-right:.5rem}.ml-2{margin-left:.5rem}.mt-4{margin-top:1rem}.ml-4{margin-left:1rem}.mt-8{margin-top:2rem}.ml-12{margin-left:3rem}.-mt-px{margin-top:-1px}.max-w-6xl{max-width:72rem}.min-h-screen{min-height:100vh}.overflow-hidden{overflow:hidden}.p-6{padding:1.5rem}.py-4{padding-top:1rem;padding-bottom:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.pt-8{padding-top:2rem}.fixed{position:fixed}.relative{position:relative}.top-0{top:0}.right-0{right:0}.shadow{--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.text-center{text-align:center}.text-gray-200{--tw-text-opacity: 1;color:rgb(229 231 235 / var(--tw-text-opacity))}.text-gray-300{--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity))}.underline{text-decoration:underline}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.w-5{width:1.25rem}.w-8{width:2rem}.w-auto{width:auto}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}@media (min-width:640px){.sm\:rounded-lg{border-radius:.5rem}.sm\:block{display:block}.sm\:items-center{align-items:center}.sm\:justify-start{justify-content:flex-start}.sm\:justify-between{justify-content:space-between}.sm\:h-20{height:5rem}.sm\:ml-0{margin-left:0}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}.sm\:pt-0{padding-top:0}.sm\:text-left{text-align:left}.sm\:text-right{text-align:right}}@media (min-width:768px){.md\:border-t-0{border-top-width:0}.md\:border-l{border-left-width:1px}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width:1024px){.lg\:px-8{padding-left:2rem;padding-right:2rem}}@media (prefers-color-scheme:dark){.dark\:bg-gray-800{--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity))}.dark\:bg-gray-900{--tw-bg-opacity: 1;background-color:rgb(17 24 39 / var(--tw-bg-opacity))}.dark\:border-gray-700{--tw-border-opacity: 1;border-color:rgb(55 65 81 / var(--tw-border-opacity))}.dark\:text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.dark\:text-gray-400{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity))}.dark\:text-gray-500{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity))}}
</style>
<style>
body {
font-family: 'Nunito', sans-serif;
}
</style>
<!-- Scripts -->
@vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body class="antialiased">
<div class="relative flex items-top justify-center min-h-screen bg-gray-100 dark:bg-gray-900 sm:items-center py-4 sm:pt-0">
@if (Route::has('login'))
<div class="hidden fixed top-0 right-0 px-6 py-4 sm:block">
@auth
<a href="{{ url('/dashboard') }}" class="text-sm text-gray-700 dark:text-gray-500 underline">Dashboard</a>
@else
<a href="{{ route('login') }}" class="text-sm text-gray-700 dark:text-gray-500 underline">Log in</a>
@if (Route::has('register'))
<a href="{{ route('register') }}" class="ml-4 text-sm text-gray-700 dark:text-gray-500 underline">Register</a>
@endif
@endauth
</div>
@endif
<div></div>
<div class="max-w-6xl mx-auto sm:px-6 lg:px-8" id="app">
</div>
</div>
</body>
</html>
此时,我们访问http://127.0.0.1:8000/就可以访问出来页面了
从数据库读取数据
为了演示从数据库中获取数据,我们在组件目录中创建另一个名为 ComponentB.vue 的组件。ComponentB.vue的内容如下
<script setup>
const props = defineProps({
user: Object
});
</script>
<template>
<h1>你好, {{ user.name }},欢迎光临</h1>
</template>
我们直接通过axios(默认自动集成)获取后端数据,在web.php文件新增一个路由,内容如下:
Route::get('/author', function () {
return response()->json(['name'=>'老俊']);
});
修改一下App.vue,获取后端数据并展示
<template>
<div>
<h1>Laravel9集成Vue3组件</h1>
<component-a></component-a>
<component-b :user="user"></component-b>
</div>
</template>
<script>
import ComponentA from './components/ComponentA.vue'
import ComponentB from './components/ComponentB.vue'
import axios from 'axios';
export default {
name: 'app',
data(){
return {
user: {
name:''
}
}
},
components:{
ComponentA,
ComponentB
},
mounted() {
axios.get('/author').then(res=>{
console.log(res)
this.user = res.data
})
},
methods:{
}
}
</script>
<style>
</style>
修改好之后,再访问http://127.0.0.1:8000/就可以看到数据了
点此获取开源代码
至此,本教程结束