诗词网站demo

这几天写了一个诗词网站的一个 demo。目的是练习 vue 以及 webpack。之所以选择诗词网站,一是手上有诗词的数据库(从一个诗词软件里拷贝过来的)。二是不算复杂,适合练手。下面回忆一下练习中碰到的问题。

文章最初分布在简书,时间为 2018.06.17 20:41 。
链接:https://www.jianshu.com/p/969f9529aa01

首先,是整体规划的问题

虽然是个小 demo,也许正因为是个小 demo ,所以没有详细规划,想到一个功能写一个功能,想到一个页面写一个页面。结果就是组件改了又改,束手束脚,后台 php 也是不停的更改。不过好歹是写出来了。差点忘了,先放一下目录结构。

./src/
|-- assets
|   |-- font
|   |   |-- iconfont.eot
|   |   |-- iconfont.svg
|   |   |-- iconfont.ttf
|   |   `-- iconfont.woff
|   |-- js
|   |   |-- base.js
|   |   `-- iconfont.js
|   `-- styles
|       |-- iconfont.css
|       `-- main.less
|-- home.html
|-- index.js
|-- index.php
`-- poem
    |-- article
    |   |-- article.html
    |   |-- article.js
    |   `-- articlebody.vue
    |-- author.vue
    |-- authors
    |   |-- authors.js
    |   `-- styles
    |       `-- authors.less
    |-- body.vue
    |-- footer.vue
    |-- header.vue
    |-- poem.vue
    |-- poems
    |   |-- pages.vue
    |   |-- poems.js
    |   `-- poemsbody.vue
    `-- search
        |-- search.js
        `-- searchbody.vue

目录比较乱。assets 目录下包含 font、js、styles。其中 base.js 并未用到。首页的文件直接在 src 文件夹下,需要的组件在 poem 文件下。其余的页面也在 poem 文件夹下。除了首页,其他页面共用 article.html 模板。实际上可以都用首页的,因为结构是一样的。

组件调用有点混乱,主要是没有统一放到一个文件夹里,而是散落在各个页面文件夹里。以后的项目还是注意点好。

二、 vue 引入的问题。

一开始写的是:

import Vue from "vue"

结果报错了,因为这句话导入的并不是 vue.js,而是vue.common.js。将其改成下面的就好了。

import Vue from "vue/dist/vue.js"

于是问题又来了,之前的练习 TodoApp 里使用的就是第一句,为什么那里没有问题呢?查看了一下代码,原来 TodoApp 里入口文件使用的是 render,而不是 components 属性。至于 vue.js 和 vue.common.js 的不同可以查考下面的文章:
Vue 2.0 升(cai)级(keng)之旅
webpack+vue的匹配报错

三、 webpack 多页面问题

关于 webpack 多页面的问题,在写这个 demo 之前就已经百度了很多,但都没弄懂。所以,一开始写这个 demo 的时候就用了一个页面一个配置文件的方法,等到写完在慢慢折腾 webpack。下面就是折腾的结果:

const config = {
  ……
  entry: {
    index: './src/index.js',
    authors: './src/poem/authors/authors.js',
    poems: './src/poem/poems/poems.js',
    search: './src/poem/search/search.js',
    article: './src/poem/article/article.js'
  },
  output: {
    filename: "js/[name].[chunkhash:8].js",
    path: path.resolve(__dirname,'dist')
  },
  ……
  plugins: [
    ……
    new HTMLPlugin({
      template: './src/home.html',
      filename: './home.html',
      chunks: ['lib','index']
    }),
    new HTMLPlugin({
      template: './src/poem/article/article.html',
      filename: 'poems.html',
      chunks: ['lib','poems']
    }),
    new HTMLPlugin({
      template: './src/poem/article/article.html',
      filename: 'authors.html',
      chunks: ['lib','authors']
    }),
    new HTMLPlugin({
      template: './src/poem/article/article.html',
      filename: 'article.html',
      chunks: ['lib','article']
    }),
    new HTMLPlugin({
      template: './src/poem/article/article.html',
      filename: 'search.html',
      chunks: ['lib','search']
    })
  ],
  ……
}

其中 lib 是拆包出来的公共库。我这里没有碰到 js 加载顺序的问题,如果有顺序问题,可以配置 html-webpack-plugin 插件的 chunksSortMode: 'manual' 解决问题。

四、 公共库打包问题

关于公共库打包折腾了很久。总体来说是配置不了解的问题。一开始配置大致如下:

  new webpack.optimize.SplitChunksPlugin({
    name:'vendor'
  }),

打包后发现,lib.js 文件确实存在了,文件也引入了,但是,其他的 js 文件体积并没有减小。(这里存在这个文件是因为有 lib 入口,而不是真的剥离公共库。)为什么?然后又是一通百度,总算找到了解决方法。SplitChunksPlugin 的配置应该这么写:

  optimization: {
    splitChunks: {
      cacheGroups: {
        lib: {
          name: 'lib',
          filename: 'js/[name].[chunkhash:8].js',
          minChunks: 2,
          chunks: 'initial'
        }
      }
    }
  }

这个 optimization 应该在 config 下面,和 entry 平级。

好了,总算解决了。

五、css 拆分的问题

嗯,实际上,这个问题还没有解决。通过 mini-css-extract-plugin 确实可以将 css 剥离出来,但是,页面没有内容,控制台也没有报错。😭

所以,css 剥离只能暂时放弃了。

六、 环境配置问题

平时为了开发方便,引入的库都是未压缩的。环境设置为 development ,但上线时需要改为 production 。为了切换方便,以及解决跨平台问题。需要使用 cross-env 插件。package.json 脚本如下:

    "build": "cross-env NODE_ENV=development webpack --config webpack.config.js && cp ./src/index.php ./dist/",
    "b_pro": "cross-env NODE_ENV=production webpack --config webpack.config.js && cp ./src/index.php ./dist/",

webpack.config.js 文件包含下面两句:

const isDev = process.env.NODE_ENV === 'development';

const config = {
  mode: isDev ? 'development' : 'production',
 ……
}

七、 清理目标文件夹

手动清理目标文件夹很不方便,所以引入 clean-webpack-plugin 插件进行清理。

const clean = require('clean-webpack-plugin');
……
  new clean(['dist']),
……

或者,在脚本里加入 linux 命令清理。(未尝试)

八、 vue 中 $emit 无法触发问题

事件名要小写。

九、 json 中 html 标签问题

因为需要将搜索的关键字在结果中高亮,所以在 php 中对结果字符串进行替换:

$result_array[$key]['d_poetry'] = str_replace($name,"<span style = \"color: red;\">".$name."</span>",$result_array[$key]['d_poetry']);

但是并没有达到预期中的结果。无论检查多少遍,尝试多少遍都不行。于是,另写一个测试文件。

<?php

$text = "一";
$obj = new StdClass();
$obj -> text = "这是一行文字";

$str = "<span style=\" color:red\" >".$text."</span>";
$obj -> text = str_replace($text,$str,$obj -> text);
echo $obj -> text;
echo "<br>"
echo json_encode($obj);

结果是什么呢?

qq 浏览器如下:

额,算了,过程比较曲折,直接说结果吧。

将 json_encode($obj) 改成 json_encode($obj,JSON_HEX_TAG)

参考:# json返回数据中带有html标签的输出

十、 url 中文转码问题

在发送请求的时候,ie 浏览器使用的不是 utf-8 编码,而是系统本地编码,比如 gbk。这样一来,中文的传输就成了问题。因为后台是 utf-8 编码。所以,我们需要对中文进行转码。

编码:

js:
url = encodeURI(encodeURI(url));

解码:

php:
url = urldecode(url);

部分 php 函数:

  • is_array()
  • count()
  • file_get_contents()
  • mysqli_connect()
  • mysqli_query()
  • mysqli_select()
  • mysqli_num_rows()
  • mysqli_fetch_all()
  • mysqli_free_result()
  • mysqli_close()
  • isset()
  • is_numeric()
  • substr()
  • urldecode()
  • unset()
  • array_unique()
  • array_rand()
  • str_replace()
  • ceil()

成品

链接:诗词

github:https://github.com/tonyzhou1890/poem