protonemedia/laravel-splade-core

此包已被废弃,不再维护。未建议替代包。

一个用于在Laravel Blade中使用Vue 3的Composition API的包。

4.0.1 2024-01-31 07:53 UTC

README

一个用于在Laravel Blade中使用Vue 3的Composition API的包。

Latest Version on Packagist GitHub Tests Action Status Splade Discord Server GitHub Sponsors

⚠️ 此包已被废弃: 关于Splade的思考:我休息了一周来四处看看并反思。

赞助Splade

我们非常珍视我们的社区支持,在我们努力创建和提供免费Laravel包的过程中。如果您觉得我们的包对您有益,并且您的工作依赖于它,我们恳请您支持赞助其维护和发展。处理问题和拉取请求是一项耗时的工作,您的帮助将非常感激。感谢您考虑我们的请求!❤️

为什么这是实验性的?

虽然这个包附带了一个全面的测试套件,但需要注意的是,它处于实验阶段。这是一个新包,我还没有在生产环境中使用过。目前,我使用原始Splade v1包来满足我的生产需求。然而,我计划在2023年第四季度将这个新包整合到两个新项目中。还值得一提的是,我尚未确认此包与原始Splade包的所有功能完全兼容。

这与现有的Laravel Splade包有什么关系?

Laravel Splade目前提供了大量功能

  • 使用Blade构建单页应用
  • 20+个交互式组件
  • 广泛的表单和表格组件
  • 模态框、滑动面板、Toast、SEO、SSR等

虽然这很好,并且极大地帮助了使用Laravel构建SPAs,但它也使得维护和扩展包变得更加困难。这就是我决定将Splade拆分成多个包的原因

  • Splade Core:此包。它仅包含在Blade中使用Vue 3的Composition API的核心功能。没有预构建的组件。没有标记。没有CSS。只是核心功能。
  • Splade Navigation:原始Splade包中的SPA和导航组件(模态框、滑动面板、Toast、SEO、SSR等)
  • Splade UI:原始Splade包中的UI组件,不包括表单和表格组件。
  • Splade Form:原始Splade包中的表单组件。
  • Splade Table:原始Splade包中的表格组件。

需求

  • PHP 8.1
  • Laravel 10
  • Vue 3.3
  • Vite 4.0

功能

  • 新项目的自动安装器
  • 在Blade模板中使用Vue 3的Composition API
  • 支持Blade组件和Blade视图
  • 从前端调用Blade组件方法
  • 从前端刷新Blade组件而无需重新加载页面
  • 使用Blade属性作为Vue属性
  • 在Blade模板中访问Js/Vue生态系统

限制

  • 内联Blade组件不受支持(模板在组件类中定义,而不是在单独的.blade.php文件中)。

安装

您可以通过composer安装此包

composer require protonemedia/laravel-splade-core

自动安装

对于新项目,您可以使用 splade:core:install Artisan 命令来自动安装该软件包

php artisan splade:core:install

这将安装 JavaScript 软件包,创建根布局和一个演示组件,并将所需的配置添加到您的 app.jsvite.config.js 文件中。运行此命令后,您可能需要运行 npm install 来安装 JavaScript 依赖项,然后运行 npm run dev 来启动 Vite。

npm install
npm run dev

手动安装

首先,您应该安装伴随的 JavaScript 软件包

npm install @protonemedia/laravel-splade-core @protonemedia/laravel-splade-vite

Splade Core 会自动为您的所有 Blade 模板生成 Vue 组件。默认情况下,它们存储在 resources/js/splade。您不需要将这些文件提交到您的仓库,因为它们在运行 Vite 时会自动生成。要初始化此目录,请运行以下命令

php artisan splade:core:initialize-directory

在您的主要 JavaScript 文件中(app.js),您必须创建一个新的 Vue 应用实例并使用 Splade Core 插件。遵循 Laravel 的约定,app.js 文件存储在 resources/js,因此您可以将相对路径 ./splade 传递给插件选项

import { createApp } from 'vue/dist/vue.esm-bundler.js'
import { SpladeCorePlugin } from '@protonemedia/laravel-splade-core'

createApp()
    .use(SpladeCorePlugin, {
        components: import.meta.glob('./splade/*.vue', { eager: true }),
    })
    .mount('#app')

在您的 vite.config.js 文件中,您必须添加 laravel-splade-vite 插件。确保在 laravelvue 插件之前添加

import { defineConfig } from 'vite'
import laravel from 'laravel-vite-plugin'
import vue from '@vitejs/plugin-vue'
import spladeCore from '@protonemedia/laravel-splade-vite'

export default defineConfig({
    plugins: [
        spladeCore(),
        laravel({
            ...
        }),
        vue({
            ...
        }),
    ],
})

最后,在您的根布局文件中,您必须为 Vue 应用创建根元素,并必须包含一个用于 Splade 模板堆栈的脚本标签。这必须在 #app 元素之前完成

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>My app</title>
        @vite("resources/js/app.js")
    </head>
    <body>
        <script> @stack('splade-templates') </script>

        <div id="app">
            {{ $slot }}
        </div>
    </body>
</html>

与 Blade 组件一起使用

您可以使用默认的 make:component Artisan 命令来生成 Blade 组件

php artisan make:component MyComponent

在 Blade 模板中,您可以使用 <script setup> 标签使您的组件具有响应性

<script setup>
const message = ref('Hello Vue!')
const uppercase = computed(() => message.value.toUpperCase())
</script>

<input v-model="message" />
<p v-text="uppercase" />

除了运行 Vite 开发服务器外,您不需要做任何其他事情。该组件将自动编译并注册为 Vue 组件。

Echo 语法

Blade 和 Vue 使用相同的花括号语法来渲染变量。这意味着您不能在模板中使用 {{ message }} 语法来渲染 Vue 变量。技术上,这是因为 Blade 编译器在 Vue 编译器之前。有两种方法可以解决这个问题

使用 v-htmlv-text 指令

<p v-text="uppercase" />

或者,使用 @ 符号来转义花括号

<p>@{{ uppercase }}</p>

组合 API 导入

在上面的第一个例子中,我们使用了 Vue 的组合 API 中的 refcomputed 函数。Splade Core 会自动为您导入这些函数。以下是所有自动导入的函数列表

  • computed
  • inject
  • nextTick
  • onActivated
  • onBeforeMount
  • onBeforeUnmount
  • onBeforeUpdate
  • onDeactivated
  • onErrorCaptured
  • onMounted
  • onUnmounted
  • onUpdated
  • provide
  • reactive
  • readonly
  • ref
  • watch
  • watchEffect
  • watchPostEffect
  • watchSyncEffect

属性继承

就像常规 Blade 组件一样,您可以使用 $attributes 变量来继承传递给组件的属性。这也适用于 v-model

这是 <x-form> 组件的模板

<script setup>
const form = ref({
    framework: 'laravel',
})
</script>

<form>
    <x-select v-model="form.framework" />
</form>

这是 <x-select> 组件的模板

<select {{ $attributes }}>
    <option value="laravel">Laravel</option>
    <option value="tailwind">Tailwind</option>
    <option value="vue">Vue</option>
</select>

带有脚本标签的组件的继承

如果您正在传递属性的组件有一个 <script> 标签,则属性将作为 Vue props 传递给组件的根元素。如果您想将属性传递给不同的元素,可以使用 v-bind="$attrs" 指令

<script setup></script>

<div class="wrapper">
    <input v-bind="$attrs" />
</div>

Splade Core 会自动检测自定义指令。

元素引用

您可以使用 $refs 变量来访问元素引用。这不在 Vue 3 的组合 API 中自然工作,但在 Vue 2 中效果很好,所以我决定在 Splade Core 中再次添加它

<script setup>
onMounted(() => {
    const creditcardEl = $refs.creditcard;
});
</script>

<input ref="creditcard" />

利用 Vue 生态系统

使用 Js/Vue 生态系统的库和包非常容易。以下是一个使用 Flatpickr 的示例。

<script setup>
import flatpickr from "flatpickr";

const emit = defineEmits(["update:modelValue"]);

onMounted(() => {
    let instance = flatpickr($refs.date, {
       onChange: (selectedDates, newValue) => {
            emit("update:modelValue", newValue);
        },
    });

    instance.setDate(props.modelValue);
});
</script>

<input ref="date" />

请注意,您可以在不定义它的前提下使用 props.modelValue。Splade Core 会自动检测 modelValue 的使用并将它添加到 props 对象中。

调用 Blade 组件上的方法

如果您的 Blade 组件有一个 public 方法,您可以从模板中调用它,无论是脚本还是模板。Splade Core 会检测当前页面的 HTTP 中间件并将其应用到后续请求。您需要做的只是给方法添加 Vue 属性。

<?php

namespace App\View\Components;

use Illuminate\View\Component;
use ProtoneMedia\SpladeCore\Attributes\Vue;

class UserProfile extends Component
{
    #[Vue]
    public function notify(string $message)
    {
        auth()->user()->notify($message);
    }

    public function render()
    {
        return view('components.user-profile');
    }
}

模板

<script setup>
const message = ref('Hey there!')
</script>

<input v-model="message" placeholder="Enter a message" />
<button @click="notify(message)">Notify User</button>
<p v-if="notify.loading">Notifying user...</p>

请注意,您可以使用 notify.loading 来检查方法是否正在运行。

警告

虽然原始中间件已应用于请求,但您仍然需要验证传入的数据。

将 Blade 变量作为 Vue Props 传递

您可以将 Blade 变量作为 Vue Props 传递。如果您想从后端传递数据到前端,这非常有用。您只需给属性添加 VueProp 属性即可。

<?php

namespace App\View\Components;

use Illuminate\View\Component;
use ProtoneMedia\SpladeCore\Attributes\VueProp;

class UserProfile extends Component
{
    #[VueProp]
    public string $defaultMessage = 'Hey there!'
}

现在您可以在模板和脚本标签中使用 defaultMessage prop。您不需要在 props 对象中指定该 prop,因为 Splade Core 会自动为您完成。

<script setup>
const defaultMessageInUpperCase = props.defaultMessage.toUpperCase();
</script>

<label>Default message:</label>
<p v-text="defaultMessage" />

将 Blade 变量作为 Vue Refs 传递

将 Blade 变量作为 Vue Refs 传递比作为 Vue Props 传递更强大。这样,您可以在模板中将变量用作响应式变量。您可以在前端更新它们,当您调用 Blade 组件方法时,后端上的值也会更新。您只需给属性添加 VueRef 属性即可。

<?php

namespace App\View\Components;

use Illuminate\View\Component;
use ProtoneMedia\SpladeCore\Attributes\VueRef;

class UserProfile extends Component
{
    #[VueRef]
    public string $notification = 'Hey there!'

    #[Vue]
    public function notify()
    {
        auth()->user()->notify($this->notification);
    }

    public function render()
    {
        return view('components.user-profile');
    }
}

模板

<script setup></script>

<input v-model="notification" placeholder="Enter a message" />
<button @click="notify">Notify User</button>

警告

小心您定义的公共属性。例如,如果您将 Eloquent 模型定义为公共属性,它将被序列化为 JSON 并传递到前端。请确保敏感属性已被 隐藏

回调函数

您也可以从脚本中调用方法,而不是从模板中调用。这样,您可以使用 thencatchfinally

<script setup>
function notifyWithFixedMessage() {
    notify('Hey there!')
        .then(() => alert('User notified!'))
        .catch(() => alert('Something went wrong!'))
        .finally(() => {
            //
        })
}
</script>

<button @click="notifyWithFixedMessage">Notify User</button>

或者,您也可以将全局回调添加到 notify 方法中。

<script setup>
notify.before((data) => {

})

notify.then((response, data) => {

})

notify.catch((e) => {

})
</script>

<input v-model="message" placeholder="Enter a message" />
<button @click="notify('Hey there!')">Notify User</button>

刷新组件

为了使组件可刷新,您必须将 Refreshable 中间件添加到路由中。

use ProtoneMedia\SpladeCore\Http\Refreshable::class;

Route::get('/login', LoginController::class)->middleware(Refreshable::class);

然后,您可以使用 refreshComponent 方法来刷新组件。这将重新渲染组件并重新获取数据。

<script setup>
const message = ref('Initial message')
</script>

<input v-model="message" placeholder="Enter a message" />
<small>User last updated: {{ auth()->user()->updated_at }}</small>
<button @click="refreshComponent">Refresh</button>

与调用 Blade 方法类似,您可以使用 refreshComponent.loading 来检查组件是否正在刷新。您还可以使用带有 refreshComponent 的回调。

与 Blade 视图一起使用

如果您不想使用 Blade 组件,您也可以使用 Blade 视图。目前,不支持重新加载 Blade 视图。

就像使用 Blade 组件一样,您可以在 Blade 视图的顶部使用 <script setup> 标签。如果您正在扩展布局,请确保将 <script setup> 标签放在 slot 中。

<x-layout>
    <script setup>
        const message = ref('Hello Vue!')
    </script>

    <input v-model="message" />
</x-layout>

包含 Blade 视图

请注意,您在每个 Blade 视图中只能使用 一个 脚本标签。例如,如果您的 Blade 视图已经有一个脚本标签,您不能使用 @include 指令包含另一个带有脚本标签的 Blade 视图。如果您想这样做,将包含的 Blade 视图转换为 Blade 组件。

变更日志

有关最近更改的详细信息,请参阅 CHANGELOG

贡献

有关详细信息,请参阅 CONTRIBUTING

安全

如果您发现任何与安全相关的问题,请通过电子邮件 pascal@protone.media 联系,而不是使用问题跟踪器。

鸣谢

许可证

MIT 许可证 (MIT)。更多信息请参阅 许可证文件