zoukankan      html  css  js  c++  java
  • Laravel Vuejs 实战:开发知乎 (10)使用 Select2 优化话题选择

    1.添加选择Topic

    使用Select2,如何安装Select2 ,具体使用实例 Select2 and Laravel: Ajax AutocompleteLoading data remotely in Select2 – Laravel

    使用命令行:

      1 composer require select2/select2

    完成后打开resourcesapp.scss,添加Select2引用:

      1 // Fonts
      2 @import url('https://fonts.googleapis.com/css?family=Nunito');
      3 
      4 // Variables
      5 @import 'variables';
      6 
      7 // Bootstrap
      8 @import '~bootstrap/scss/bootstrap';
      9 
     10 // Select2
     11 @import 'vendor/select2/select2/src/scss/core.scss';
     12 
    打开resourcesapp.js文件,添加select2引用:

      1 require('../../vendor/select2/select2/dist/js/select2.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 
     10 window.Vue = require('vue');
     11 
     12 /**
     13  * The following block of code may be used to automatically register your
     14  * Vue components. It will recursively scan this directory for the Vue
     15  * components and automatically register them with their "basename".
     16  *
     17  * Eg. ./components/ExampleComponent.vue -> <example-component></example-component>
     18  */
     19 
     20 // const files = require.context('./', true, /.vue$/i)
     21 // files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default))
     22 
     23 Vue.component('example-component', require('./components/ExampleComponent.vue').default);
     24 
     25 /**
     26  * Next, we will create a fresh Vue application instance and attach it to
     27  * the page. Then, you may begin adding components to this application
     28  * or customize the JavaScript scaffolding to fit your unique needs.
     29  */
     30 
     31 const app = new Vue({
     32     el: '#app',
     33 });

    然后执行命令:

      1 npm install & npm run dev

    注意:原教程中采用@include('vendor.ueditor.assets') 方式引用了ueditor的js代码, 在Laravel vue中 打开chrome console会看到有异常提示,便将其中代码分拆:

    一部分移入app.js中:一定要注意这个顺序,否则可能出现百度富文本编辑器UE.getEditor is not a function 异常:

      1 // 将views/vendor/ueditor/assets.blade.php中的引用换到本处
      2 require('../../public/vendor/ueditor/ueditor.config.js');
      3 require('../../public/vendor/ueditor/ueditor.all.js');

    批注 2020-02-28 211826

    然后,

      1 window.UEDITOR_CONFIG.serverUrl = "{{ config('ueditor.route.name') }}";

    移入app.blade.php中

    批注 2020-02-28 211715

    最后,将ueditor需要的dialogs,lang,php,themes,third-party文件夹移入public/js文件夹内:

    批注 2020-02-28 211755

    还要记得删除 create.blade.php中的引用语句:@include('vendor.ueditor.assets')


    在webpack.mix.js使用mix.version();添加版本控制,防止多次更新浏览器缓存导致效果没显示的问题。

      1 const mix = require('laravel-mix');
      2 
      3 /*
      4  |--------------------------------------------------------------------------
      5  | Mix Asset Management
      6  |--------------------------------------------------------------------------
      7  |
      8  | Mix provides a clean, fluent API for defining some Webpack build steps
      9  | for your Laravel application. By default, we are compiling the Sass
     10  | file for the application as well as bundling up all the JS files.
     11  |
     12  */
     13 
     14 mix.js('resources/js/app.js', 'public/js')
     15     .sass('resources/sass/app.scss', 'public/css');
     16 mix.version();
    添加mix.version()


    打包完成后,参考多选使用方法示例,再创建问题的view blade文件中添加一个位置用来选问题的Topic:

    如:

      1 <div class="form-group">
      2     <label for="topic_list">选择主题</label>
      3     <select id="topic_list" class="js-example-basic-multiple" name="topics[]"
      4             multiple="multiple">
      5         <option value="AL">Alabama</option>
      6         <option value="WY">Wyoming</option>
      7     </select>
      8 </div>
    添加选择位

    为了更规范,我们将create.blade.php中的js代码放进一个section,并在app.blade.php中使用yield放置:

      1 <!doctype html>
      2 <html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
      3 <head>
      4     <meta charset="utf-8">
      5     <meta name="viewport" content="width=device-width, initial-scale=1">
      6 
      7     {{--    CSRF Token--}}
      8     <meta name="csrf-token" content="{{ csrf_token() }}">
      9 
     10     <title>{{ config('app.name', 'Laravel') }}</title>
     11 
     12 
     13     {{--    Fonts--}}
     14     <link rel="dns-prefetch" href="//fonts.gstatic.com">
     15     <link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet">
     16 
     17     {{--    Styles--}}
     18     <link href="{{ mix('css/app.css') }}" rel="stylesheet">
     19 
     20 </head>
     21 <body>
     22 <div id="app">
     23     <nav class="navbar navbar-expand-md navbar-light bg-white shadow-sm">
     24         <div class="container">
     25             <a class="navbar-brand" href="{{ url('/') }}">
     26                 {{ config('app.name', 'Laravel') }}
     27             </a>
     28             <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent"
     29                     aria-controls="navbarSupportedContent" aria-expanded="false"
     30                     aria-label="{{ __('Toggle navigation') }}">
     31                 <span class="navbar-toggler-icon"></span>
     32             </button>
     33 
     34             <div class="collapse navbar-collapse" id="navbarSupportedContent">
     35                 {{--                Left Side Of Navbar--}}
     36                 <ul class="navbar-nav mr-auto">
     37 
     38                 </ul>
     39 
     40                 {{--                Right Side Of Navbar--}}
     41                 <ul class="navbar-nav ml-auto">
     42                     {{--                    Authentication Links--}}
     43                     @guest
     44                         <li class="nav-item">
     45                             <a class="nav-link" href="{{ route('login') }}">{{ __('Login') }}</a>
     46                         </li>
     47                         @if (Route::has('register'))
     48                             <li class="nav-item">
     49                                 <a class="nav-link" href="{{ route('register') }}">{{ __('Register') }}</a>
     50                             </li>
     51                         @endif
     52                     @else
     53                         <li class="nav-item dropdown">
     54                             <a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button"
     55                                data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre>
     56                                 {{ Auth::user()->name }} <span class="caret"></span>
     57                             </a>
     58 
     59                             <div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
     60                                 <a class="dropdown-item" href="{{ route('logout') }}"
     61                                    onclick="event.preventDefault();
     62                                                      document.getElementById('logout-form').submit();">
     63                                     {{ __('Logout') }}
     64                                 </a>
     65 
     66                                 <form id="logout-form" action="{{ route('logout') }}" method="POST"
     67                                       style="display: none;">
     68                                     @csrf
     69                                 </form>
     70                             </div>
     71                         </li>
     72                     @endguest
     73                 </ul>
     74             </div>
     75         </div>
     76     </nav>
     77 
     78     <main class="py-4">
     79         @include('flash::message')
     80         @yield('content')
     81     </main>
     82 </div>
     83 {{--Scripts--}}
     84 <script src="{{ mix('js/app.js') }}"></script>
     85 
     86 <script>
     87     $('#flash-overlay-modal').modal();
     88     window.UEDITOR_CONFIG.serverUrl = "{{ config('ueditor.route.name') }}";
     89 </script>
     90 @yield('footer-js')
     91 </body>
     92 </html>
    app.blade.php中添加js插槽
      1 @extends('layouts.app')
      2 @section('content')
      3     <div class="container">
      4         <div class="row">
      5             <div class="col-md-8 col-md-offset-2">
      6                 <div class="card">
      7                     <div class="card-header">
      8                         发布问题
      9                     </div>
     10                     <div class="card-body">
     11                         <form action="{{ route('questions.store') }}" method="post">
     12                             {{--注意要有csrftoken--}}
     13                             @csrf
     14                             <div class="form-group">
     15                                 <label for="title">标题</label>
     16                                 <input type="text" name="title" class="form-control" placeholder="标题" id="title"
     17                                        value="{{ old('title') }}">
     18                                 <p class="text text-danger"> @error('title') {{ $message }} @enderror </p>
     19                             </div>
     20                             <!-- Select2 Topic Select -->
     21                             <div class="form-group">
     22                                 <label for="topic_list">选择主题</label>
     23                                 <select id="topic_list" class="js-example-basic-multiple form-control" name="topics[]"
     24                                         multiple="multiple">
     25                                     <option value="AL">Alabama</option>
     26                                     <option value="WY">Wyoming</option>
     27                                 </select>
     28                             </div>
     29                             <!-- 编辑器容器 -->
     30                             <script id="container" name="content" type="text/plain"
     31                                     style=" 100%">{!! old('content') !!}</script>
     32                             <p class="text text-danger"> @error('content') {{ $message }} @enderror </p>
     33                             <!--发布按钮-->
     34                             <button type="submit" class="btn btn-primary mt-2 float-md-right">发布问题</button>
     35                         </form>
     36                     </div>
     37                 </div>
     38             </div>
     39         </div>
     40     </div>
     41 @endsection
     42 @section('footer-js')
     43     <script type="text/javascript">
     44         // 实例化编辑器
     45         var ue = UE.getEditor('container', {
     46             toolbars: [
     47                 ['bold', 'italic', 'underline', 'strikethrough', 'blockquote', 'insertunorderedlist', 'insertorderedlist', 'justifyleft', 'justifycenter', 'justifyright', 'link', 'insertimage', 'fullscreen']
     48             ],
     49             elementPathEnabled: false,
     50             enableContextMenu: false,
     51             autoClearEmptyNode: true,
     52             wordCount: false,
     53             imagePopup: false,
     54             autotypeset: {indent: true, imageBlockLine: 'center'}
     55         });
     56         ue.ready(function () {
     57             ue.execCommand('serverparam', '_token', '{{ csrf_token() }}'); // 设置 CSRF token.
     58         });
     59         $(document).ready(function () {
     60             // Select2多选js
     61             $('.js-example-basic-multiple').select2();
     62         });
     63     </script>
     64 @endsection
    create.blade.php中js放进section

    初始效果如下:

    批注 2020-02-28 212605

    接下来使用ajax实现数据请求填充,具体参考 additional-examples,作者原代码链接:Laravel 实战开发知乎使用 Select2 的相关代码

    编辑后create.blade.php代码如下:

      1 @extends('layouts.app')
      2 @section('content')
      3     <div class="container">
      4         <div class="row">
      5             <div class="col-md-8 col-md-offset-2">
      6                 <div class="card">
      7                     <div class="card-header">
      8                         发布问题
      9                     </div>
     10                     <div class="card-body">
     11                         <form action="{{ route('questions.store') }}" method="post">
     12                             {{--注意要有csrftoken--}}
     13                             @csrf
     14                             <div class="form-group">
     15                                 <label for="title">标题</label>
     16                                 <input type="text" name="title" class="form-control" placeholder="标题" id="title"
     17                                        value="{{ old('title') }}">
     18                                 <p class="text text-danger"> @error('title') {{ $message }} @enderror </p>
     19                             </div>
     20                             <!-- Select2 Topic Select -->
     21                             <div class="form-group">
     22                                 <label for="topic_list">选择主题</label>
     23                                 <select id="topic_list" class="js-example-basic-multiple form-control" name="topics[]"
     24                                         multiple="multiple">
     25                                     <option value="AL">Alabama</option>
     26                                     <option value="WY">Wyoming</option>
     27                                 </select>
     28                             </div>
     29                             <!-- 编辑器容器 -->
     30                             <script id="container" name="content" type="text/plain"
     31                                     style=" 100%">{!! old('content') !!}</script>
     32                             <p class="text text-danger"> @error('content') {{ $message }} @enderror </p>
     33                             <!--发布按钮-->
     34                             <button type="submit" class="btn btn-primary mt-2 float-md-right">发布问题</button>
     35                         </form>
     36                     </div>
     37                 </div>
     38             </div>
     39         </div>
     40     </div>
     41 @endsection
     42 @section('footer-js')
     43     <script type="text/javascript">
     44         // 实例化编辑器
     45         var ue = UE.getEditor('container', {
     46             toolbars: [
     47                 ['bold', 'italic', 'underline', 'strikethrough', 'blockquote', 'insertunorderedlist', 'insertorderedlist', 'justifyleft', 'justifycenter', 'justifyright', 'link', 'insertimage', 'fullscreen']
     48             ],
     49             elementPathEnabled: false,
     50             enableContextMenu: false,
     51             autoClearEmptyNode: true,
     52             wordCount: false,
     53             imagePopup: false,
     54             autotypeset: {indent: true, imageBlockLine: 'center'}
     55         });
     56         ue.ready(function () {
     57             ue.execCommand('serverparam', '_token', '{{ csrf_token() }}'); // 设置 CSRF token.
     58         });
     59         $(document).ready(function () {
     60             // Select2多选js
     61             $('.js-example-basic-multiple').select2({
     62                 // 设置属性及初始化值
     63                 tags: true,
     64                 placeholder: '选择相关话题',
     65                 miniumInputLength: 2,
     66 
     67                 ajax: {
     68                     url: '/api/topics',
     69                     dataType: 'json',
     70                     // Additional AJAX parameters go here; see the end of this chapter for the full code of this example
     71                     delay: 250,
     72                     data: function (params) {
     73                         return {
     74                             q: params.term, // search term
     75                             // page: params.page 暂时不需要分页
     76                         };
     77                     },
     78                     processResults: function (data, params) {
     79                         // 解析结果为Select2期望的格式
     80                         // parse the results into the format expected by Select2
     81                         // since we are using custom formatting functions we do not need to
     82                         // alter the remote JSON data, except to indicate that infinite
     83                         // scrolling can be used
     84                         return {
     85                             results: data
     86                         };
     87                     },
     88                     cache: true,
     89                 },
     90                 //模板样式
     91                 templateResult: formatTopic,
     92                 //模板样式 【选择项】
     93                 templateSelection: formatTopicSelection,
     94                 escapeMarkup: function (markup) {
     95                     return markup;
     96                 }
     97             });
     98         });
     99 
    100         //格式化话题
    101         function formatTopic(topic) {
    102             return "<div class='select2-result-repository clearfix'>" +
    103             "<div class='select2-result-repository__meta'>" +
    104             "<div class='select2-result-repository__title'>" +
    105             topic.name ? topic.name : "Laravel" +
    106                 "</div></div></div>";
    107         }
    108 
    109         //格式化话题选项
    110         function formatTopicSelection(topic) {
    111             return topic.name || topic.text;
    112         }
    113     </script>
    114 @endsection
    create.blade.php js使用ajax

    现在请求的js写好了,我们需要提供ajax api请求的路由及请求时候要的数据,使用faker生成:

    (1)在api.php文件中添加路由:

      1 Route::middleware('api')->get('/topics', function (Request $request) {
      2     $query = $request->query('q');
      3     return AppTopic::query()->where('name', 'like', '%' . $query . '%')->get();
      4 });

    路由测试可以通过打开如:http://zhihu.test/api/topics?q=Americ 链接查看结果的方式,这里没有数据,我们先添加示例数据:

    (2)执行命令添加一个Factory:

    关于工厂可以参考:

    laravel 利用factory数据填充

    Laravel Model Factory(模型工厂)的用法以及数据本地化

    laravel 使用测试工厂Factory添加测试数据

    进一步可以了解一下seeder:

    Laravel学习笔记之Seeder填充数据小技巧

      1 php artisan make:factory TopicFactory

    打开生成的TopicFactory.php工厂文件,修改如下:

      1 <?php
      2 
      3 /** @var IlluminateDatabaseEloquentFactory $factory */
      4 
      5 use AppTopic;
      6 use FakerGenerator as Faker;
      7 
      8 $factory->define(Topic::class, function (Faker $faker) {
      9     return [
     10         //
     11         'name' => $faker->name,
     12         'content' => $faker->paragraph,
     13         'questions_count' => $faker->numberBetween(1, 10),
     14     ];
     15 });

    执行命令打开tinker:

    关于tinker可以查看:

    PHP laravel系列之PHP Artisan Tinker 

    使用 Php Artisan Tinker 来调试你的 Laravel

    以上两篇文章讲解已经很丰富,官方文档也提供了讲解

      1 php artisan tinker

    使用factory方法生成30个topic:

      1 factory(AppTopic::class,30)->create();

      1 use AppTopic;
      2 factory(Topic::class,30)->create();
    

    批注 2020-02-28 215923

    数据生成完毕,

    删除create.blade.php中的option

      1 <select id="topic_list" class="js-example-basic-multiple form-control" name="topics[]"
      2                                         multiple="multiple">
      3                                     <option value="AL">Alabama</option>
      4                                     <option value="WY">Wyoming</option>
      5                                 </select>
      1 @extends('layouts.app')
      2 @section('content')
      3     <div class="container">
      4         <div class="row">
      5             <div class="col-md-8 col-md-offset-2">
      6                 <div class="card">
      7                     <div class="card-header">
      8                         发布问题
      9                     </div>
     10                     <div class="card-body">
     11                         <form action="{{ route('questions.store') }}" method="post">
     12                             {{--注意要有csrftoken--}}
     13                             @csrf
     14                             <div class="form-group">
     15                                 <label for="title">标题</label>
     16                                 <input type="text" name="title" class="form-control" placeholder="标题" id="title"
     17                                        value="{{ old('title') }}">
     18                                 <p class="text text-danger"> @error('title') {{ $message }} @enderror </p>
     19                             </div>
     20                             <!-- Select2 Topic Select -->
     21                             <div class="form-group">
     22                                 <label for="topic_list">选择主题</label>
     23                                 <select id="topic_list" class="js-example-basic-multiple form-control"
     24                                         name="topics[]" multiple></select>
     25                             </div>
     26                             <!-- 编辑器容器 -->
     27                             <script id="container" name="content" type="text/plain"
     28                                     style=" 100%">{!! old('content') !!}</script>
     29                             <p class="text text-danger"> @error('content') {{ $message }} @enderror </p>
     30                             <!--发布按钮-->
     31                             <button type="submit" class="btn btn-primary mt-2 float-md-right">发布问题</button>
     32                         </form>
     33                     </div>
     34                 </div>
     35             </div>
     36         </div>
     37     </div>
     38 @endsection
     39 @section('footer-js')
     40     <script type="text/javascript">
     41         // 实例化编辑器
     42         var ue = UE.getEditor('container', {
     43             toolbars: [
     44                 ['bold', 'italic', 'underline', 'strikethrough', 'blockquote', 'insertunorderedlist', 'insertorderedlist', 'justifyleft', 'justifycenter', 'justifyright', 'link', 'insertimage', 'fullscreen']
     45             ],
     46             elementPathEnabled: false,
     47             enableContextMenu: false,
     48             autoClearEmptyNode: true,
     49             wordCount: false,
     50             imagePopup: false,
     51             autotypeset: {indent: true, imageBlockLine: 'center'}
     52         });
     53         ue.ready(function () {
     54             ue.execCommand('serverparam', '_token', '{{ csrf_token() }}'); // 设置 CSRF token.
     55         });
     56         $(document).ready(function () {
     57             // Select2多选js
     58             $('.js-example-basic-multiple').select2({
     59                 // 设置属性及初始化值
     60                 tags: true,
     61                 placeholder: '选择相关话题',
     62                 miniumInputLength: 2,
     63 
     64                 ajax: {
     65                     url: '/api/topics',
     66                     dataType: 'json',
     67                     // Additional AJAX parameters go here; see the end of this chapter for the full code of this example
     68                     delay: 250,
     69                     data: function (params) {
     70                         return {
     71                             // term : The current search term in the search box.
     72                             //     q : Contains the same contents as term.
     73                             // _type: A "request type". Will usually be query, but changes to query_append for paginated requests.
     74                             // page : The current page number to request. Only sent for paginated (infinite scrolling) searches.
     75                             q: params.term, // search term
     76                             // page: params.page 暂时不需要分页
     77                         };
     78                     },
     79                     processResults: function (data, params) {
     80                         // 解析结果为Select2期望的格式
     81                         // parse the results into the format expected by Select2
     82                         // since we are using custom formatting functions we do not need to
     83                         // alter the remote JSON data, except to indicate that infinite
     84                         // scrolling can be used
     85                         return {
     86                             results: data
     87                         };
     88                     },
     89                     cache: true,
     90                 },
     91                 //模板样式
     92                 templateResult: formatTopic,
     93                 //模板样式 【选择项】
     94                 templateSelection: formatTopicSelection,
     95                 escapeMarkup: function (markup) {
     96                     return markup;
     97                 }
     98             });
     99         });
    100 
    101         //格式化话题
    102         function formatTopic(topic) {
    103             return "<div class='select2-result-repository clearfix'>" +
    104             "<div class='select2-result-repository__meta'>" +
    105             "<div class='select2-result-repository__title'>" +
    106             topic.name ? topic.name : "Laravel" +
    107                 "</div></div></div>";
    108         }
    109 
    110         //格式化话题选项
    111         function formatTopicSelection(topic) {
    112             return topic.name || topic.text;
    113         }
    114     </script>
    115 @endsection
    create.blade.php删除option后完整代码

    刷新页面测试效果:

    批注 2020-02-28 230311

    我们通过dd()方法查看一下请求:

    批注 2020-02-28 230756

    可以看到,如果请求的topic在数据库中找到了,传入的是topic在表中的id,

    如果是用户自己新增的在数据库中找不到,则传入用户设置的值。

  • 相关阅读:
    【Stanford Machine Learning Open Course】1. 机器学习介绍
    【Stanford Machine Learning Open Course】3. 线性回归问题两种解法:正规方程组解法 & 梯度下降法
    【linux】crontab周期性/定时启动任务
    【python】 IOError: [Errno 32] Broken pipe
    关注性能:循环的耗时及编译优化的影响
    【Linux】shell: 获取时间间隔到毫秒、微秒级别
    【Stanford Machine Learning Open Course】4. 特征优化
    【Stanford Machine Learning Open Course】2. 线性回归问题介绍
    拖延处理技巧汇编摘自《拖延心理学》
    JavaFx版本植物大战僵尸
  • 原文地址:https://www.cnblogs.com/dzkjz/p/12377481.html
Copyright © 2011-2022 走看看