zoukankan      html  css  js  c++  java
  • vue+uikit3+laravel快速建站

    vue+uikit3+laravel快速建站

    vue+uikit3+laravel快速建站

    目前站已初步建好,待完善中,https://recallsufuture.space,源码已放到 github

    1 前言

    很早因为折腾科学上网之术,入了vps的坑,然而那个配置只是作为梯子的话实在是浪费资源, 在加上做了一阵子的web开发,却还没自己的一个站,自己的小程序做不了,网站总可以的嘛, 那么下面就开始吧。

    2 需求

    实际上还真不知到要做个什么样的网站,经过一番艰难的思考,还是决定先做已经被我做烂了的fa爬虫, 如果有其他的想法,就做成新的板块,这样就可以慢慢填坑啦。

    2.1 页面

    • 主页面,展示本站作用以及现有板块
    • fa板块,批量爬取原图链接

    3 环境

    3.1 开发环境

    • php7.2
    • npm
    • composer
    • vscode
    • redis
    • chrome & firefox

    3.2 生产环境

    • oneinstack一键环境,包括php,nginx,redis。
    • npm
    • composer

    3.3 框架

    • 前端用vue+uikit3制作足够模块化且现代化的页面,并用vue-router来提供路由支持
    • 后端用laravel,优雅且强大

    4 Let's code

    4.1 主页面

    4.1.1 界面构思

    这个页面需要有顶部导航栏,主体需要有足够大而鲜明的说明标题文字来介绍本站, 标题下面是几个card来展示现有的板块。

    4.1.2 实现

    首先是路由,默认的laravel用闭包写了一个welcome路由,这个我们不需要了,删掉routes/web.php内的这行路由, 并删掉对应的blade文件。

    因为我用了vue-router来管理路由,所以只需要在web.php中写一个拦截所有请求的路由即可,所有页面请求都导向vue页面, 即:

    Route::get('/{view?}', 'HomeController@index')->where('view', '.*')->name('home');
    

    接着修改上面的HomeController的index方法,使它返回app.blade.php模板

    <!DOCTYPE html>
    <html lang="{{ app()->getLocale() }}">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
    
        <!-- CSRF Token -->
        <meta name="csrf-token" content="{{ csrf_token() }}">
    
        <title>夙的小站</title>
    
        <!-- Styles -->
        <link href="{{ mix('css/app.css') }}" rel="stylesheet">
    </head>
    <body>
        <div id="app"></div>
    
        <!-- Scripts -->
        <script src="{{ mix('js/app.js') }}"></script>
    </body>
    </html>
    
    

    因为要用到uikit,所以去找了下脚手架,在网站根目录执行下面四条命令可以获得vue+uikit3脚手架:

    composer require laravel-frontend-presets/uikit3
    php artisan preset uikit3
    php artisan preset vue
    npm install
    

    添加vue-router路由配置文件router.js:

    import Vue from 'vue'
    import Router from 'vue-router'
    
    Vue.use(Router);
    
    export default new Router({
        mode: 'history',
        routes: [
            {
                path: '/',
                redirect: '/home',
            },
            {
                path: '/home',
                component: require('./pages/Home.vue'),
            },
        ],
    })
    
    

    修改下app.js保证编译顺利通过,然后就可以开始在resources/assets/js/pages/Home.vue里写第一个vue页面啦。

    此处省略一千字。。。直接看结果吧

    website1.png

    4.2 fa页面

    最初的想法是先将图片下到服务器,完成后打包发给用户,但实验过后发现等待时间实在太长, 一旦关了浏览器就啥都没有了,而且这样做很费服务器空间,没办法,只能退而求其次,获取来所有的链接让用户自己去下载。

    那么这个页面一共有如下几个内容:

    • 界面内需要一个表单来获取一些下载信息
    • 后台暴露出一个接口,由前端ajax访问此接口,这样可以有比较好的体验
    • 界面上要有一个公告窗口,记录当前的下载日志
    • 后台需要配合实现websocket广播功能

    前台界面的编写就不再多说,直接看下成品图 website2.png

    后台部分,首先要实现那个接口,也就是接受表单数据,处理,然后返回状态码。

    当然,还是得先把路由写好:

    <?php
    
    Route::prefix('api')->group(function () {
        // 批量获取fa链接
        Route::get('/fa', 'FaController@index')->name('fa.index');
    });
    
    // 全部拦截到此页
    Route::get('/{view?}', 'HomeController@index')->where('view', '.*')->name('home');
    

    因为可能还会有其他的api,所以我在这里分组并设置了统一的路径前缀(web.php参考了Laravel Horizon)

    然后是编写FaController,用php artisan命令创建controller,并修改其中的index方法:

    <?php
    
    namespace AppHttpControllers;
    
    use IlluminateHttpRequest;
    
    use AppEventsFaDownloadEvent;
    
    class FaController extends Controller
    {
        /**
         * 返回是否成功新建任务
         *
         * @return IlluminateHttpResponse
         */
        public function index(Request $request)
        {
            // 验证表单
            $validatedData = $request->validate([
                'id'      => "filled",
                'name'    => "required|max:255",
                'type'    => [
                    "required",
                    "regex:/gallery|scraps/"
                ],
                'pagenum' => "min:1",
                'picnum'  => "min:1|max:72",
                'maxnum'  => "min:0"
            ]);
    
            // 保存表单数据
            $id      = $validatedData['id'];
            $name    = trim($validatedData['name']);
            $type    = $validatedData['type'];
            $pagenum = $validatedData['pagenum'];
            $picnum  = $validatedData['picnum'];
            $maxnum  = $validatedData['maxnum'];
    
            event(new FaDownloadEvent($id, $name, $type, $pagenum, $picnum, $maxnum));
    
            return [
                'status' => 'ok'
            ];
        }
    }
    
    

    可以看到我先是验证了表单数据,然后将数据保存下来并触发了一个事件,验证表单数据是因为作为api, 有可能会被其他地方的代码访问,所以必须要验证数据有效性,而不直接下载改为触发事件是因为需要异步执行下载, 将下载任务放到队列里,通过广播来通知客户进度。

    这里涉及到了事件,队列和广播,通过触发事件,预先设定好的的监听器会接受事件并处理,这样可以让代码更加解耦。 队列是用来处理需要长时间运行的任务,比如发送邮件。广播是为了和让后台和浏览器即使的沟通, 利用 websocket 建立长连接,免除了ajax轮询的麻烦,具体的内容请查询laravel中文文档

    下面一个个说这些功能的实现:

    4.2.1 事件

    当前有一个FaDownloadEvent事件,这个事件接收所有表单参数,至于代码部分,其实十分的简单:

    <?php
    
    namespace AppEvents;
    
    use IlluminateBroadcastingChannel;
    use IlluminateQueueSerializesModels;
    use IlluminateBroadcastingPrivateChannel;
    use IlluminateBroadcastingPresenceChannel;
    use IlluminateFoundationEventsDispatchable;
    use IlluminateBroadcastingInteractsWithSockets;
    use IlluminateContractsBroadcastingShouldBroadcast;
    
    class FaDownloadEvent
    {
        use Dispatchable, InteractsWithSockets, SerializesModels;
    
        /**
         * Client id
         *
         * @var string
         */
        public $id;
    
        /**
         * Author name
         *
         * @var string
         */
        public $name;
    
        /**
         * Gallery or scraps
         *
         * @var string
         */
        public $type;
    
        /**
         * Start page number
         *
         * @var string
         */
        public $pagenum;
    
        /**
         * Start pic number
         *
         * @var string
         */
        public $picnum;
    
        /**
         * Max download num
         *
         * @var string
         */
        public $maxnum;
    
        /**
         * Create a new event instance.
         *
         * @return void
         */
        public function __construct($id, $name, $type, $pagenum, $picnum, $maxnum)
        {
            $this->id = $id;
            $this->name = $name;
            $this->type = $type;
            $this->pagenum = $pagenum;
            $this->picnum = $picnum;
            $this->maxnum = $maxnum;
        }
    }
    
    

    只是通过构造函数将参数保存到成员变量里而已,接下来看看接收这个事件的监听器:

    4.2.2 监听器

    <?php
    
    namespace AppListeners;
    
    use AppEventsFaDownloadEvent;
    use AppEventsDownloadStateEvent;
    use AppModelsFile;
    use AppUtilityVendorFaFurAffinityAPI;
    
    use IlluminateQueueInteractsWithQueue;
    use IlluminateContractsQueueShouldQueue;
    
    class FaDownloadListener implements ShouldQueue
    {
        /**
         * The number of seconds the job can run before timing out.
         *
         * @var int
         */
        public $timeout = 1000;
    
        /**
         * Handle the event.
         *
         * @param  FaDownloadEvent  $event
         * @return void
         */
        public function handle(FaDownloadEvent $event)
        {
            // 触发一个状态事件,此事件会向浏览器广播下面的内容
            event(new DownloadStateEvent($id, 'info', '正在下载'.$name.'/'.$type.'的第'.$nowpage.'页第'. $nowpic .'个链接'));
    
            // 下面是具体的下载逻辑,在此省略
        }
    }
    
    

    监听器类接受到事件后,就可以进行下载任务了,但是如果直接开始的话,下载过程还会是同步的, 也就是会阻塞浏览器,让它变成异步只需要简单的添加一个接口就可以啦,

    class FaDownloadListener implements ShouldQueu
    

    只要加上这个接口,任务的执行就会自动放到队列里,至于是哪个队列呢?当然是默认队列啦

    4.2.3 队列

    现在需要配置队列,队列可以看作是一个单独的进程,这个进程就是个死循环,有任务放进来就执行,没有就睡眠等待

    配置起来也不难,首先修改.env,将队列设置为redis驱动: QUEUEDRIVER=redis

    然后在网站根目录下执行: php artisan queue:worker 即可,这样就开启了一个默认的队列。 想要开启更多的不一样的队列?用 –queue 参数试试。

    不过这个进程会一直堵塞着终端,毕竟是个死循环嘛, 不想看到一直堵塞着的话可以让它后台执行: php artisan queue:worker –daemon >> /dev/null &

    这个队列配置好后,监听器就可以正常工作了,每接收到一个FaDownloadEvent事件,就会向默认队列中添加一个下载任务。

    4.2.4 广播

    现在只剩广播部分没有完成

    Date: 2018-07-26 18:36

    Author: su

    Created: 2018-07-29 日 16:00

    Validate

  • 相关阅读:
    C++基础知识篇:C++ 存储类
    听说高手都用记事本写C语言代码?那你知道怎么编译运行吗?
    培训机构出来的程序员和科班比?看看这个科班毕业生怎么说~
    C++基础知识篇:C++ 修饰符类型
    从大学毕业到就业,程序员的人生如何走过?30岁以后的开发人员路在何方?
    终于有人把鸿蒙OS讲明白了,大佬讲解!快收藏!
    C++基础知识篇:C++ 常量
    Portrait Matting
    Deep-Trimap-Generation-for-Automatic-Video-Matting-using-GAN
    Automatic Trimap Generator
  • 原文地址:https://www.cnblogs.com/recallfuture/p/9373901.html
Copyright © 2011-2022 走看看