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 ...
随机推荐
- AD转化器分类及特点和选用
1. AD转换器的分类 下面简要介绍常用的几种类型的基本原理及特点:积分型.逐次逼近型.并行比较型/串并行型.∑-Δ调制型.电容阵列逐次比较型及压频变换型. 1)积分型(如TLC7135)积分型AD工 ...
- HTML连载61-焦点图、固定定位
一.焦点图 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF ...
- STL 萃取(Traits)机制剖析
模板特化 在将萃取机制之前,先要说明模板特化 当有两个模板类,一个是通用泛型模板,一个是特殊类型模板,如果创建一个特殊类型的对象,会优先调用特殊的类型模板类,例如: template <type ...
- C++-HDU1394-Minimum Inversion Number[数据结构][树状数组]
给出0~n-1的一个排列,可以整体移动,求逆序对最小值 把数字num[i]的加入,等价于树状数组的第n-num[i]位加1 因为num[i]是第 (n-1)-num[i]+1=n-num[i]大的数字 ...
- AcWing 900. 整数划分
#include <iostream> #include <algorithm> using namespace std; , mod = 1e9 + ; int n; int ...
- 2.7 Axure rp (快速原型设计工具)
一. Axure rp 下载安装 直接百度栏输入Axure rp即可下载.安装无特别处,一直点击下一步即可. 安装的如果是英文版,可以下载汉化包,进行汉化. 汉化参照网址:http://www.a ...
- HBase 中 Memstore-Local Allocation Buffer
在0.90 版本后的 HBase,引入了一个高级机制用于缓解堆内存碎片的问题.此内存碎片问题的产生的主要原因是由于 memstore 上的扰动(频繁的分配与释放内存空间)导致.对应解决此问题的机制为M ...
- LeetCode第144场周赛总结
5117.IP地址无效化 首先计算出输入IP地址的长度,然后遍历每一个字符. 如果当前字符为'.',就在它的前后两侧分别加上'['和']'字符. 值得一提的是,C++的String类型提供了以上操作的 ...
- Django_Setings
""" Django settings for untitled1 project. Generated by 'django-admin startproject' u ...
- python面试的100题(1)
题目:有一个jsonline格式的文件file.txt大小约为10K def get_lines(): with open('file.txt','rb') as f: return f.readli ...