Laravel Vuejs 实战:开发知乎 (10)使用 Select2 优化话题选择
1.添加选择Topic
使用Select2,如何安装Select2 ,具体使用实例 Select2 and Laravel: Ajax Autocomplete 及 Loading data remotely in Select2 – Laravel
使用命令行:
1 composer require select2/select2
完成后打开resources\app.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
打开resources\app.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');
然后,
1 window.UEDITOR_CONFIG.serverUrl = "{{ config('ueditor.route.name') }}";移入app.blade.php中
最后,将ueditor需要的dialogs,lang,php,themes,third-party文件夹移入public/js文件夹内:
还要记得删除 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="width: 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
初始效果如下:
接下来使用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="width: 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 \App\Topic::query()->where('name', 'like', '%' . $query . '%')->get();
4 });
路由测试可以通过打开如:http://zhihu.test/api/topics?q=Americ 链接查看结果的方式,这里没有数据,我们先添加示例数据:
(2)执行命令添加一个Factory:
关于工厂可以参考:
Laravel Model Factory(模型工厂)的用法以及数据本地化
进一步可以了解一下seeder:
1 php artisan make:factory TopicFactory
打开生成的TopicFactory.php工厂文件,修改如下:
1 <?php
2
3 /** @var \Illuminate\Database\Eloquent\Factory $factory */
4
5 use App\Topic;
6 use Faker\Generator 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(App\Topic::class,30)->create();
或
1 use App\Topic;
2 factory(Topic::class,30)->create();
数据生成完毕,
删除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="width: 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后完整代码
刷新页面测试效果:
我们通过dd()方法查看一下请求:
可以看到,如果请求的topic在数据库中找到了,传入的是topic在表中的id,
如果是用户自己新增的在数据库中找不到,则传入用户设置的值。
Laravel Vuejs 实战:开发知乎 (10)使用 Select2 优化话题选择的更多相关文章
- Laravel Vuejs 实战:开发知乎 (6)发布问题
1.view部分: 安装一个扩展包:Laravel-UEditor composer require "overtrue/laravel-ueditor:~1.0" 配置 添加下面 ...
- Laravel Vuejs 实战:开发知乎 (9)定义话题与问题关系
1.话题[Topic] 执行命令: php artisan make:model Topic –cmr 修改****_**_**_create_topics_table.php数据库迁移文件如下: c ...
- Laravel Vuejs 实战:开发知乎 (8)美化编辑器
1.使用UEditor增量包: simple-ueditors 执行下载: git clone https://github.com/JellyBool/simple-ueditor.git 2.用此 ...
- Laravel Vuejs 实战:开发知乎 (2)用户登录
1.安装一个给用户提示的扩展包: 二选一: https://github.com/laracasts/flash [我选的这个]https://github.com/oanhnn/laravel-fl ...
- Laravel Vuejs 实战:开发知乎 (2)用户注册
1.本节需要发送验证邮件 2.教程使用SendCloud发送邮件 [我使用的是mailtrap] 3. composer require laravel/ui 安装完成后 php artisan ui ...
- Laravel Vuejs 实战:开发知乎 (1)项目环境配置和用户表设计
1.使用laragon新建laravel项目 zhihu 2.配置env文件的database设置 DB_DATABASE=zhihu 3.分析users表需要的字段 4.修改数据库迁移文件: cla ...
- Laravel Vuejs 实战:开发知乎 (5)设计问题表
1.执行命令: php artisan make:model Models/Question -cm 2.设计问题的数据库迁移文件中的字段: <?php use Illuminate\Datab ...
- Laravel Vuejs 实战:开发知乎 (7)验证问题表单字段
上一节代码中已经实现 下面代码中的validate内部配置就是: public function store(Request $request) { // $data = $request->v ...
- Laravel Vuejs 实战:开发知乎 (3)本地化和自定义消息
1.本地化 由于所有blade默认采用的是 _('')方式输出标签文本,所以可以安装一个语言包,直接指定本地语言为zh_CN即可: 安装 https://github.com/caouecs/Lara ...
随机推荐
- python3 读取串口数据
python3 读取串口数据 demo import serial import time ser = serial.Serial("COM3",115200,timeout = ...
- 【Python】BMI指数 计算器
身体质量指数 (Body Mass Index, 简称BMI), 亦称克托莱指数, 是目前国际上常用的衡量人体胖瘦程度以及是否健康的一个标准.BMI 值超标,意味着你必须减肥了. 在线版:https: ...
- Python :元组,不可修改的序列
- 在多租户(容器)数据库中如何创建PDB:方法6 DBCA本地克隆PDB
基于版本:19c (12.2.0.3) AskScuti 创建方法:DBCA静默本地克隆PDB.根据 CDB1 中的 PDB1 克隆出 CDB1 中的 PDB_CLONE 对应路径:Creating ...
- python3练习100题——026
原题链接:http://www.runoob.com/python/python-exercise-example26.html 题目:利用递归方法求5!. 是25题递归方式的简化版所以很容易. 我的 ...
- SpringCloud大白话之服务注册中心
SpringCloud-Eureka白话说明 eureka.client.register-with-eureka 属性表示是否将自己注册到Eureka Server, 默认为true. 由于当前应用 ...
- vue.js + element中el-select实现拼音匹配,分词、缩写、多音字匹配能力
1.既然要用到拼音搜索,我们就需要一个拼音库,在这里我推荐一个第三方包:https://github.com/xmflswood/pinyin-match,在这里首先对这个包的开发者表示万分的感谢. ...
- 题解【Codeforces886B】Vlad and Cafes
本题是模拟题. 我们可以用b数组记录每个数字在a数组中出现的最后位置,然后从0到2·10^5依次寻找最后一次出现最早的数(注意是0!),最后统计输出即可. AC代码: #include <bit ...
- 转载:reverb
https://blog.csdn.net/qiumingjian/article/details/43938687 https://blog.csdn.net/jsjwangmingmin/arti ...
- 励志成为优产的母猪--------猜数游戏 ,历史记录,pickle保存,队列deque
# pickle 可以处理复杂的序列化语法.(例如自定义的类的方法,游戏的存档等),存档以文件的形式保存 参见 https://www.cnblogs.com/abobo/p/8080447.html ...