项目踩坑系列(一)——vue-cli

2018-06-01  本文已影响0人  LuLuX

文章内容大概包括:

因为搭建新项目需要,自己搞了一下webpack的东西。之前使用大多是别人搭好的架构,自己新建项目拿来用就好了,没有去自己动手搭过。现在就纯记录一下:

选脚手架 vue-cli

需求:一个完整的网站,包括首页、列表页、详情页、播放页等等约30个左右的页面。
同事推荐用cooking或者vue-cli搭建架构,cooking之前已经有在几个项目中实践过,据描述并不是很好用,配置有些没暴露,有些loader不好配。大概搞了一下之后决定用vue-cli。

先用npm全局安装vue-cli,还有vue-init,然后执行init来装webpack+vue,初始化项目的时候在命令行有一些选项要配置一下,初始化完成之后进入对应的项目,装一下各种依赖包。装完之后就可以直接npm run dev跑一下啦,美滋滋。详细的步骤可以参考网上的文章,搜一下很多这方面的内容。

npm install -g @vue/cli
npm install -g @vue/cli-init
vue init webpack my-project
cd my-project
npm install

vue适合做单页应用,但是领导要求页面要做多页(原公司的项目有多页的,但是代码在原电脑里,所以时下也不方便去找),就网上找了下vue多页的配置。翻了一下之后找了一篇参考:使用Vue-cli搭建多页面应用时对项目结构和配置的调整来实际操作,按照文章来实际操作,没什么问题。但是每个页面都放了一个入口的html文件感觉比较麻烦,于是稍微做了一点调整。在上面文章的基础上修改了build/utils.js文件,把所有页面的入口文件都改成放在外面,不需要每个页面都放置一个入口模板(具体代码看后面)。

大概调整后的目录结构如下:

项目整体目录情况 多页,pages目录如下

几个坑

配置过程中遇到的主要问题是:
1、在各种依赖包都安装完了的情况下,如果修改项目名,在跑npm run dev的时候会直接报错。用万能的搜索引擎找了一下原因:npm项目,在安装依赖(node_nodules)时,会记录当前的文件路径,当修改之后就无法正常启动。也是比较蛋疼的,需要删除node_modules目录,再重新npm install。解决方案如下:

2、在跑npm install的时候,虽然自己已经设置了科学上网,但是还是会有一些依赖包装不了,所以还是借助淘宝npm镜像cnpm来安装。一行命令就搞定,然后cnpm install美滋滋。虽然网上有人吐槽cnpm有时候会出现漏包的情况,不过我这边跑起来暂时没遇到这种情况。

npm install -g cnpm --registry=https://registry.npm.taobao.org

3、build打包的问题。在npm run build的时候,因为一开始我的pages目录是这样子的:

错误示范

虽然是在pages里面创建了不同命名的文件夹index live user,但是入口html和js文件都是使用index命名的,导致在build的时候生成的dist目录下,只有一个index.html和index.js。然后我就方了,不是说多页面吗,怎么只有一个入口html和js。

遂重新去看了使用Vue-cli搭建多页面应用时对项目结构和配置的调整 文章下修改的具体配置,找到了build/utils.js文件下的配置,发现了它不是取pages目录下文件夹的名字作为打包完之后入口html和js文件的命名,而是直接取了文件夹内对应文件的名字,并将生成的文件都放在一个目录下,所以就直接覆盖了。

我这里就很尴尬的三个目录下的文件名都是index。于是对uilts.js文件进行修改,将html和js都修改成:直接提取pages文件夹下的子文件夹的名字,作为 build完之后生成的html和js文件的命名。避免了pages不同目录下的文件名不能重复的情况,同时因为个人习惯,把不同目录下的入口js文件都命名为index.js,方便查看。

调整后的pages目录如下(这里我删去了之前的index.html,在第三步中说明):

调整pages目录

3、pages目录下的每个子目录,都有index.html一个模板入口文件,内容都是一样的,每个目录下放一个相同的文件感觉不太喜欢,遂做一点修改,将其提取出来放在src目录下,所有页面都用同一个模板来生成。

结合2和3的修改,utils.js某个模块调整如下:

// yanzi 这块是对js的调整
//多入口配置
// 通过glob模块读取pages文件夹下的所有对应文件夹下的js后缀文件,如果该文件存在
// 那么就作为入口处理
exports.entries = function() {
    var entryFiles = glob.sync(PAGE_PATH + '/*') //从原来的提取js路径作为filename改为提取目录路径
    var map = {}
    entryFiles.forEach((filePath) => {
        let filename = filePath.split('/').pop() //从目录路径中提取目录名,作为build完js文件的命名
        map[filename] = filePath + '/index.js' //不同页面的入口js统一命名为index.js
    })
    return map
}

// yanzi 这块是对html的调整
//多页面输出配置
// 与上面的多页面入口配置相同,读取pages文件夹下的对应的html后缀文件,然后放入数组中
exports.htmlPlugin = function() {
    let entryHtml = glob.sync(PAGE_PATH + '/*') //从原来的提取html路径作为filename改为提取目录路径
    let arr = []
    
    entryHtml.forEach((filePath) => {
        let filename =  filePath.split('/').pop(); //从目录路径中提取目录名,作为build完html文件的命名
        let conf = {
            // 模板来源
            // template: filePath,
            template: path.resolve(__dirname, '../index.html'), //将模板来源改为src目录下的index.html
            // 文件名称
            filename: filename + '.html',
            // 页面模板需要加对应的js脚本,如果不加这行则每个页面都会引入所有的js脚本
            chunks: ['manifest', 'vendor', filename],
            inject: true
        }
        if (process.env.NODE_ENV === 'production') {
            conf = merge(conf, {
                minify: {
                    removeComments: true,
                    collapseWhitespace: true,
                    removeAttributeQuotes: true
                },
                chunksSortMode: 'dependency'
            })
        }
        arr.push(new HtmlWebpackPlugin(conf))
    })
    return arr
}

路由的去中心化管理

因为页面比较多,搭完项目之后开始搞路由。

user页面结构

user是一个页面入口,下面有主页面App.vue以及subPages目录下的多个页面。而subPages目录下的页面,如myVideos文件夹中还有另外的subPages,大概两层路由的情况。

在编写页面路由的时候,普通的做法是把所有vue文件都在外层的router.js中引入,包括子页面的子页面。这样引入的工作量比较大(引入路径也长),而且集中在外层管理不太方便,生成的路由也会非常大难以管理。

所以,做了一个去中心化的管理。每个subPages下的页面,都配有自己的routes.js路由,然后在外层的router.js再集中引入。用到的webpack属性是require.context

首先,在subPages各个目录下先编写好自己子目录的路由,如myVIdeos/routes.js的代码如下:

const myVideos = () => import('./myVideos.vue')
const myRecord = () => import('./subPages/myRecord.vue')
const videoList = () => import('./subPages/videoList.vue')

module.exports = [
  {
    path: '/myVideos',
    component: myVideos,
    name: 'myVideos',
    children: [
      {
        path: 'myRecord',
        name: 'myRecord',
        component: myRecord
      },{
        path: 'videoList',
        component: videoList,
        name: 'videoList'
      }
    ]
  }
]

然后再在外层的router.js文件中,遍历subPages目录下的各个routes.js文件,动态加载,集中输出。router.js代码如下:

// 动态加载各模块路由,./subPages/xx/routes.js
export default [].concat(...(r => {
  return r.keys().map((key) => {
    return r(key).map(route => {
      return {
        path: route.path,
        name: route.name,
        component: route.component,
        children: route.children || []
      }
    })
  })
})(require.context('./subPages', true, /^\.(\/\w+)+\/routes\.js$/i)))

页面动态标题

title更新思路:
1、简单粗暴的document.title='啦啦啦啦'
2、插件 vue-router-title,直接在meta里面赋title的值。vue-wechat-title 针对微信的标题做一些兼容处理
3、使用vue的自定义指令:注册一个全局指令,v-title
举两个栗子:

// 栗子一
Vue.directive('title', {
  // 当被绑定的元素插入到 DOM 中时……
  inserted: function (el, binding) {
    document.title = el.innerText
    el.remove()
  }
})
<div v-title>这是标题</div>
//栗子二
Vue.directive('title', {
  // 当被绑定的元素插入到 DOM 中时……
  inserted: function (el, binding) {
    binding.value
  }
})
<div v-title="这是标题"></div>

4、使用slot和组件的生命周期:写一个title组价来更新document.title,写起来更像在页面<title>里面写

参考:
vue2.0 下对网页标题(document.title)更新的一种实现思路
vue-router-title
vue-wechat-title

打包遇到的问题

1、打完包(npm run build)在预览的时候,样式和开发模式下有一些出入,对比发现css缺少了-webkit-box-orient: vertical属性。参考:https://segmentfault.com/q/1010000009360389

因为项目中用到这个属性的地方可能比较多,懒得一个一个去修改/*! autoprefixer: off *//* autoprefixer: on */,所以采取的方案是直接在webpack.prod.conf.js中关闭了OptimizeCSSPlugin~

一些比较细的小坑

1、因为后端的数据库没有对emoji做支持,临时将数据库的编码改成utf8mb4,时间上也来不及。所以暂时先由前端这边做处理,把用户输入的emoji表情过滤掉。用个正则/(\ud83c[\udf00-\udfff])|(\ud83d[\udc00-\ude4f])|(\ud83d[\ude80-\udeff])/匹配,提示用户“不支持表情”。【好像在前司也处理过这个问题。。】

2、<input type="number">,因为e也是一个数字,但是对于我们简单的输入100以内整数的操作,不需要e,所以增加个处理,也是正则匹配只能输入数字,如下:

onkeypress='return( /[\d]/.test(String.fromCharCode(event.keyCode)))'

对于用户的输入法设置为英文的时候,这个处理是ok的。但是在用户的输入法设置为中文的时候,输入dede,再按个shift键把中文转为英文,输入框的内容会变成ee。所以这种处理还是存在bug的。

输入法设置为英文 输入法设置为中文 中文输入dede 变为ee

3、使用<input type="file">上传文件,一般是监听change事件来做处理,但是如果前后添加的是同一文件,那么change事件不会被触发。解决的思路是在文件上传完之后清空前面的值。

推荐汇总:

上一篇 下一篇

猜你喜欢

热点阅读