您的当前位置:首页正文

vue-cli3 项目优化之通过 node 自动生成组件模板 generate View、Component

2023-12-06 来源:站点网
导读这次给大家带来如何优化Vue,优化Vue的注意事项有哪些,下面就是实战案例,一起来看一下。在vue的使用过程中会遇到各种场景,当普通使用时觉得没什么,但是或许优化一下可以更高效更优美的进行开发。下面有一些我在日常开发的时候用到的小技巧,在下将不定期更新~1. 多图表resize事件去中心化1.1 一般情况有时候我们会遇到这样的场景,一个组件中有几个图表,在浏览器resize的时候我们希望图表也进行resize,因此我们会在父容器组件中写:mounted() {setTimeout(() =>

介绍

做前端的大家都知道通过 vue 开发的项目每次创建新组建的时候,都要新建一个目录,然后新增 .vue 文件,在这个文件中再写入 template 、 script 、 style 这些内容,虽然在写入的时候大家都有自己的自动补全共计,不过这些都是模板性的,每次都要这样重复操作,很麻烦有没有。

本文就是通过node来帮助我们,自动去执行这些重复操作,而我们只需要告诉控制台我们需要创建的组件名字就可以了。本文自动创建的组件包含两个文件:入口文件 index.js 、vue文件 main.vue

chalk工具

为了方便我们能看清控制台输出的各种语句,我们先安装一下 chalk

npm install chalk --save-dev

1. 创建views

在根目录中创建一个 scripts 文件夹

  • 在 scripts 中创建 generateView 文件夹
  • 在 generateView 中新建 index.js ,放置生成组件的代码
  • 在 generateView 中新建 template.js ,放置组件模板的代码,模板内容可根据项目需求自行修改
  • index.js

    // index.jsconst chalk = require('chalk')const path = require('path')const fs = require('fs')const resolve = (...file) => path.resolve(__dirname, ...file)const log = message => console.log(chalk.green(`${message}`))const successLog = message => console.log(chalk.blue(`${message}`))const errorLog = error => console.log(chalk.red(`${error}`))// 导入模板const { vueTemplate, entryTemplate} = require('./template')// 生成文件const generateFile = (path, data) => { if (fs.existsSync(path)) { errorLog(`${path}文件已存在`) return } return new Promise((resolve, reject) => { fs.writeFile(path, data, 'utf8', err => { if (err) { errorLog(err.message) reject(err) } else { resolve(true) } }) })}log('请输入要生成的页面组件名称、会生成在 views/目录下')let componentName = ''process.stdin.on('data', async chunk => { // 组件名称 const inputName = String(chunk).trim().toString() // Vue页面组件路径 const componentPath = resolve('../../src/views', inputName) // vue文件 const vueFile = resolve(componentPath, 'main.vue') // 入口文件 const entryFile = resolve(componentPath, 'entry.js') // 判断组件文件夹是否存在 const hasComponentExists = fs.existsSync(componentPath) if (hasComponentExists) { errorLog(`${inputName}页面组件已存在,请重新输入`) return } else { log(`正在生成 component 目录 ${componentPath}`) await dotExistDirectoryCreate(componentPath) } try { // 获取组件名 if (inputName.includes('/')) { const inputArr = inputName.split('/') componentName = inputArr[inputArr.length - 1] } else { componentName = inputName } log(`正在生成 vue 文件 ${vueFile}`) await generateFile(vueFile, vueTemplate(componentName)) log(`正在生成 entry 文件 ${entryFile}`) await generateFile(entryFile, entryTemplate(componentName)) successLog('生成成功') } catch (e) { errorLog(e.message) } process.stdin.emit('end')})process.stdin.on('end', () => { log('exit') process.exit()})function dotExistDirectoryCreate(directory) { return new Promise((resolve) => { mkdirs(directory, function() { resolve(true) }) })}// 递归创建目录function mkdirs(directory, callback) { var exists = fs.existsSync(directory) if (exists) { callback() } else { mkdirs(path.dirname(directory), function() { fs.mkdirSync(directory) callback() }) }}

    template.js

    // template.jsmodule.exports = { vueTemplate: compoenntName => { return `<template> <div class="${compoenntName}"> ${compoenntName}组件 </div></template><script>export default { name: '${compoenntName}'};</script><style lang="stylus" scoped>.${compoenntName} {};</style>` }, entryTemplate: compoenntName => { return `import ${compoenntName} from './main.vue'export default [{ path: "/${compoenntName}", name: "${compoenntName}", component: ${compoenntName}}]` }}

    1.1 配置package.json

    "new:view": "node ./scripts/generateView/index"

    如果使用 npm 的话 就是 npm run new:view如果是 yarn 自行修改命令

    1.2 结果

    2. 创建component

    跟views基本一样的步骤

  • 在 scripts 中创建 generateComponent 文件夹
  • 在 generateComponent 中新建 index.js ,放置生成组件的代码
  • 在 generateComponent 中新建 template.js ,放置组件模板的代码,模板内容可根据项目需求自行修改
  • index.js

    // index.js`const chalk = require('chalk')const path = require('path')const fs = require('fs')const resolve = (...file) => path.resolve(__dirname, ...file)const log = message => console.log(chalk.green(`${message}`))const successLog = message => console.log(chalk.blue(`${message}`))const errorLog = error => console.log(chalk.red(`${error}`))const { vueTemplate, entryTemplate} = require('./template')const generateFile = (path, data) => { if (fs.existsSync(path)) { errorLog(`${path}文件已存在`) return } return new Promise((resolve, reject) => { fs.writeFile(path, data, 'utf8', err => { if (err) { errorLog(err.message) reject(err) } else { resolve(true) } }) })}log('请输入要生成的组件名称、如需生成全局组件,请加 global/ 前缀')let componentName = ''process.stdin.on('data', async chunk => { const inputName = String(chunk).trim().toString() /** * 组件目录路径 */ const componentDirectory = resolve('../../src/components', inputName) /** * vue组件路径 */ const componentVueName = resolve(componentDirectory, 'main.vue') /** * 入口文件路径 */ const entryComponentName = resolve(componentDirectory, 'index.js') const hasComponentDirectory = fs.existsSync(componentDirectory) if (hasComponentDirectory) { errorLog(`${inputName}组件目录已存在,请重新输入`) return } else { log(`正在生成 component 目录 ${componentDirectory}`) await dotExistDirectoryCreate(componentDirectory) // fs.mkdirSync(componentDirectory); } try { if (inputName.includes('/')) { const inputArr = inputName.split('/') componentName = inputArr[inputArr.length - 1] } else { componentName = inputName } log(`正在生成 vue 文件 ${componentVueName}`) await generateFile(componentVueName, vueTemplate(componentName)) log(`正在生成 entry 文件 ${entryComponentName}`) await generateFile(entryComponentName, entryTemplate) successLog('生成成功') } catch (e) { errorLog(e.message) } process.stdin.emit('end')})process.stdin.on('end', () => { log('exit') process.exit()})function dotExistDirectoryCreate(directory) { return new Promise((resolve) => { mkdirs(directory, function() { resolve(true) }) })}// 递归创建目录function mkdirs(directory, callback) { var exists = fs.existsSync(directory) if (exists) { callback() } else { mkdirs(path.dirname(directory), function() { fs.mkdirSync(directory) callback() }) }}

    template.js

    // template.jsmodule.exports = { vueTemplate: compoenntName => { return `<template> <div class="${compoenntName}"> ${compoenntName}组件 </div></template><script>export default { name: '${compoenntName}'};</script><style lang="stylus" scoped>.${compoenntName} {};</style>` }, entryTemplate: `import Main from './main.vue'export default Main`}

    2.1 配置package.json

    "new:comp": "node ./scripts/generateComponent/index"

  • 如果使用 npm 的话 就是 npm run new:comp
  • 如果是 yarn 自行修改命令
  • 2.2 结果

    通过以上的 vue-cli3 优化,我们项目在开发的过程中就能非常方便的通过命令快速创建公共组件和其他页面了,在页面、组件比较多的项目中,可以为我们提高一些效率,也可以通过这样的命令,来控制团队内不同人员新建文件的格式规范。

    总结

    以上所述是小编给大家介绍的vue-cli3 项目优化之通过 node 自动生成组件模板 generate View、Component,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的!

    小编还为您整理了以下内容,可能对您也有帮助:

    如何优化Vue


    这次给大家带来如何优化Vue,优化Vue的注意事项有哪些,下面就是实战案例,一起来看一下。
    在vue的使用过程中会遇到各种场景,当普通使用时觉得没什么,但是或许优化一下可以更高效更优美的进行开发。下面有一些我在日常开发的时候用到的小技巧,在下将不定期更新~
    1. 多图表resize事件去中心化
    1.1 一般情况
    有时候我们会遇到这样的场景,一个组件中有几个图表,在浏览器resize的时候我们希望图表也进行resize,因此我们会在父容器组件中写:
    mounted() {
    setTimeout(() => window.onresize = () => {
    this.$refs.chart1.chartWrapperDom.resize()
    this.$refs.chart2.chartWrapperDom.resize()
    // ...
    }, 200)
    destroyed() { window.onresize = null }这样子图表组件如果跟父容器组件不在一个页面,子组件的状态就被放到父组件进行管理,为了维护方便,我们自然希望子组件的事件和状态由自己来维护,这样在添加删除组件的时候就不需要去父组件挨个修改
    1.2 优化
    这里使用了lodash的节流throttle函数,也可以自己实现,这篇文章也有节流的实现可以参考一下。 以Echarts为例,在每个图表组件中:
    computed: {
    /**
    * 图表DOM
    */
    chartWrapperDom() {
    const dom = document.getElementById('consume-analy-chart-wrapper')
    return dom && Echarts.init(dom)
    },
    /**
    * 图表resize节流,这里使用了lodash,也可以自己使用setTimout实现节流
    */
    chartResize() {
    return _.throttle(() => this.chartWrapperDom && this.chartWrapperDom.resize(), 400)
    }
    },
    mounted() {
    window.addEventListener('resize', this.chartResize)
    },
    destroyed() {
    window.removeEventListener('resize', this.chartResize)
    }2. 全局过滤器注册
    2.1 一般情况
    官方注册过滤器的方式:
    export default {
    data () { return {} },
    filters:{
    orderBy (){
    // doSomething
    },
    uppercase () {
    // doSomething
    }
    }
    }但是我们做项目来说,大部分的过滤器是要全局使用的,不会每每用到就在组件里面去写,抽成全局的会更好些。官方注册全局的方式:
    // 注册
    Vue.filter('my-filter', function (value) {
    // 返回处理后的值
    })
    // getter,返回已注册的过滤器
    var myFilter = Vue.filter('my-filter')但是分散写的话不美观,因此可以抽出成单独文件。
    2.2 优化
    我们可以抽出到独立文件,然后使用Object.keys在main.js入口统一注册 /src/common/filters.js
    let dateServer = value => value.replace(/(d{4})(d{2})(d{2})/g, '$1-$2-$3')
    export { dateServer }
    /src/main.js
    import * as custom from './common/filters/custom'
    Object.keys(custom).forEach(key => Vue.filter(key, custom[key]))然后在其他的.vue 文件中就可愉快地使用这些我们定义好的全局过滤器了
    <template>
    <section class="content">
    <p>{{ time | dateServer }}</p> <!-- 2016-01-01 -->
    </section>
    </template>
    <script>
    export default {
    data () {
    return {
    time: 20160101
    }
    }
    }
    </script>3. 全局组件注册
    3.1 一般情况
    需要使用组件的场景:
    <template>
    <BaseInput v-model="searchText" @keydown.enter="search"/>
    <BaseButton @click="search">
    <BaseIcon name="search"/>
    </BaseButton>
    </template>
    <script>
    import BaseButton from './baseButton'
    import BaseIcon from './baseIcon'
    import BaseInput from './baseInput'
    export default {
    components: { BaseButton, BaseIcon, BaseInput }
    }
    </script>我们写了一堆基础UI组件,然后每次我们需要使用这些组件的时候,都得先import,然后声明components,很繁琐,这里可以使用统一注册的形式
    3.2 优化
    我们需要借助一下神器webpack,使用 require.context() 方法来创建自己的 模块 上下文,从而实现自动动态require组件。这个方法需要3个参数:要搜索的文件夹目录、是否还应该搜索它的子目录、以及一个匹配文件的正则表达式。 我们在components文件夹添加一个叫componentRegister.js的文件,在这个文件里借助webpack动态将需要的基础组件统统打包进来。 /src/components/componentRegister.js
    import Vue from 'vue'
    /**
    * 首字母大写
    * @param str 字符串
    * @example heheHaha
    * @return {string} HeheHaha
    */
    function capitalizeFirstLetter(str) {
    return str.charAt(0).toUpperCase() + str.slice(1)
    }
    /**
    * 对符合'xx/xx.vue'组件格式的组件取组件名
    * @param str fileName
    * @example abc/bcd/def/basicTable.vue
    * @return {string} BasicTable
    */
    function validateFileName(str) {
    return /^S+.vue$/.test(str) &&
    str.replace(/^S+/(w+).vue$/, (rs, $1) => capitalizeFirstLetter($1))
    }
    const requireComponent = require.context('./', true, /.vue$/)
    // 找到组件文件夹下以.vue命名的文件,如果文件名为index,那么取组件中的name作为注册的组件名
    requireComponent.keys().forEach(filePath => {
    const componentConfig = requireComponent(filePath)
    const fileName = validateFileName(filePath)
    const componentName = fileName.toLowerCase() === 'index'
    ? capitalizeFirstLetter(componentConfig.default.name)
    : fileName
    Vue.component(componentName, componentConfig.default || componentConfig)
    })这里文件夹结构:
    components
    │ componentRegister.js
    ├─BasicTable
    │ BasicTable.vue
    ├─MultiCondition
    │ index.vue这里对组件名做了判断,如果是index的话就取组件中的name属性处理后作为注册组件名,所以最后注册的组件为: multi-condition 、 basic-table 最后我们在main.js中import 'components/componentRegister.js',然后我们就可以随时随地使用这些基础组件,无需手动引入了~
    4. 不同路由的组件复用
    4.1 场景还原
    当某个场景中vue-router从/post-page/a,跳转到/post-page/b。然后我们惊人的发现,页面跳转后数据竟然没更新?!原因是vue-router"智能地"发现这是同一个组件,然后它就决定要复用这个组件,所以你在created函数里写的方法压根就没执行。通常的解决方案是监听$route的变化来初始化数据,如下:
    data() {
    return {
    loading: false,
    error: null,
    post: null
    }
    },
    watch: {
    '$route': { // 使用watch来监控是否是同一个路由
    handler: 'resetData',
    immediate: true
    }
    },
    methods: {
    resetData() {
    this.loading = false
    this.error = null
    this.post = null
    this.getPost(this.$route.params.id)
    },
    getPost(id){ }
    }4.2 优化
    那要怎么样才能实现这样的效果呢,答案是给 router-view 添加一个不同的key,这样即使是公用组件,只要url变化了,就一定会重新创建这个组件。
    <router-view :key="$route.fullpath"></router-view>还可以在其后加 + +new Date() 时间戳,保证独一无二
    5. 高阶组件
    5.1 一般情况
    // 父组件
    <BaseInput :value="value"
    label="密码"
    placeholder="请填写密码"
    @input="handleInput"
    @focus="handleFocus">
    </BaseInput>
    // 子组件
    <template>
    <label>
    {{ label }}
    <input :value=" value"
    :placeholder="placeholder"
    @focus="$emit('focus', $event)"
    @input="$emit('input', $event.target.value)">
    </label>
    </template>5.2 优化
    1 每一个从父组件传到子组件的props,我们都得在子组件的Props中显式的声明才能使用。这样一来,我们的子组件每次都需要申明一大堆props, 而类似placeholer这种dom原生的property我们其实完全可以使用 $attrs 直接从父传到子,无需声明。方法如下:
    <input :value="value"
    v-bind="$attrs"
    @input="$emit('input', $event.target.value)">$attrs 包含了父作用域中不作为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定,并且可以通过 v-bind="$attrs" 传入内部组件——在创建更高层次的组件时非常有用。
    2 注意到子组件的 @focus="$emit('focus', $event)" 其实什么都没做,只是把event传回给父组件而已,那其实和上面类似,完全没必要显式地申明:
    <input :value="value"
    v-bind="$attrs"
    v-on="listeners"/>
    computed: {
    listeners() {
    return {
    ...this.$listeners,
    input: event =>
    this.$emit('input', event.target.value)
    }
    }
    }$listeners 包含了父作用域中的 (不含 .native 修饰器的)v-on 事件*。它可以通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用。
    需要注意的是,由于我们input并不是BaseInput这个组件的根节点,而默认情况下父作用域的不被认作 props 的特性绑定将会“回退”且作为普通的 HTML 特性应用在子组件的根元素上。所以我们需要设置 inheritAttrs: false ,这些默认行为将会被去掉,以上两点的优化才能成功。
    6. 路由根据开发状态懒加载
    6.1 一般情况
    一般我们在路由中加载组件的时候:
    import Login from '@/views/login.vue'
    export default new Router({
    routes: [{ path: '/login', name: '登陆', component: Login}]
    })当你需要懒加载 lazy-loading 的时候,需要一个个把routes的component改为 () => import('@/views/login.vue') ,甚为麻烦。
    当你的项目页面越来越多之后,在开发环境之中使用 lazy-loading 会变得不太合适,每次更改代码触发热更新都会变得非常的慢。所以建议只在生成环境之中使用路由懒加载功能。
    6.2 优化
    根据Vue的异步组件和Webpack的代码分割功能可以轻松实现组件的懒加载,如:
    const Foo = () => import('./Foo.vue')
    在区分开发环境与生产环境时,可以在路由文件夹下分别新建两个文件: _import_proction.js
    mole.exports = file => () => import('@/views/' + file + '.vue')
    _import_development.js ,这种写法 vue-loader 版本至少v13.0.0以上
    mole.exports = file => require('@/views/' + file + '.vue').default
    而在设置路由的 router/index.js 文件中:
    const _import = require('./_import_' + process.env.NODE_ENV)
    export default new Router({
    routes: [{ path: '/login', name: '登陆', component: _import('login/index') }]
    })这样组件在开发环境下就是非懒加载,生产环境下就是懒加载的了
    7 vue-loader小技巧
    vue-loader 是处理 *.vue 文件的 webpack loader。它本身提供了丰富的 API,有些 API 很实用但很少被人熟知。例如接下来要介绍的 preserveWhitespace 和 transformToRequire
    7.1 用 preserveWhitespace 减少文件体积
    有些时候我们在写模板时不想让元素和元素之间有空格,可能会写成这样:
    <ul>
    <li>1111</li><li>2222</li><li>333</li>
    </ul>当然还有其他方式,比如设置字体的 font-size: 0 ,然后给需要的内容单独设置字体大小,目的是为了去掉元素间的空格。其实我们完全可以通过配置 vue-loader 实现这一需求。
    {
    vue: {
    preserveWhitespace: false
    }
    }它的作用是阻止元素间生成空白内容,在 Vue 模板编译后使用 _v(" ") 表示。如果项目中模板内容多的话,它们还是会占用一些文件体积的。例如 Element 配置该属性后,未压缩情况下文件体积减少了近 30Kb。
    7.2 使用 transformToRequire 再也不用把图片写成变量了
    以前在写 Vue 的时候经常会写到这样的代码:把图片提前 require 传给一个变量再传给组件。
    <template>
    <p>
    <avatar :default-src="DEFAULT_AVATAR"></avatar>
    </p>
    </template>
    <script>
    export default {
    created () {
    this.DEFAULT_AVATAR = require('./assets/default-avatar.png')
    }
    }
    </script>其实通过配置 transformToRequire 后,就可以直接配置,这样vue-loader会把对应的属性自动 require 之后传给组件
    {
    vue: {
    transformToRequire: {
    avatar: ['default-src']
    }
    }
    }于是我们代码就可以简化不少
    <template>
    <p>
    <avatar default-src="./assets/default-avatar.png"></avatar>
    </p>
    </template>在 vue-cli 的 webpack 模板下,默认配置是:
    transformToRequire: {
    video: ['src', 'poster'],
    source: 'src',
    img: 'src',
    image: 'xlink:href'
    }可以举一反三进行一下类似的配置
    vue-loader 还有很多实用的 API 例如最近加入的自定义块,感兴趣的各位可以去文档里找找看。
    8. render 函数
    在某些场景下你可能需要render 渲染函数带来的完全编程能力来解决不太容易解决的问题,特别是要动态选择生成标签和组件类型的场景。
    8.1 动态标签
    1. 一般情况
    比如根据props来生成标签的场景
    <template>
    <p>
    <p v-if="level === 1&

    如何优化Vue


    这次给大家带来如何优化Vue,优化Vue的注意事项有哪些,下面就是实战案例,一起来看一下。
    在vue的使用过程中会遇到各种场景,当普通使用时觉得没什么,但是或许优化一下可以更高效更优美的进行开发。下面有一些我在日常开发的时候用到的小技巧,在下将不定期更新~
    1. 多图表resize事件去中心化
    1.1 一般情况
    有时候我们会遇到这样的场景,一个组件中有几个图表,在浏览器resize的时候我们希望图表也进行resize,因此我们会在父容器组件中写:
    mounted() {
    setTimeout(() => window.onresize = () => {
    this.$refs.chart1.chartWrapperDom.resize()
    this.$refs.chart2.chartWrapperDom.resize()
    // ...
    }, 200)
    destroyed() { window.onresize = null }这样子图表组件如果跟父容器组件不在一个页面,子组件的状态就被放到父组件进行管理,为了维护方便,我们自然希望子组件的事件和状态由自己来维护,这样在添加删除组件的时候就不需要去父组件挨个修改
    1.2 优化
    这里使用了lodash的节流throttle函数,也可以自己实现,这篇文章也有节流的实现可以参考一下。 以Echarts为例,在每个图表组件中:
    computed: {
    /**
    * 图表DOM
    */
    chartWrapperDom() {
    const dom = document.getElementById('consume-analy-chart-wrapper')
    return dom && Echarts.init(dom)
    },
    /**
    * 图表resize节流,这里使用了lodash,也可以自己使用setTimout实现节流
    */
    chartResize() {
    return _.throttle(() => this.chartWrapperDom && this.chartWrapperDom.resize(), 400)
    }
    },
    mounted() {
    window.addEventListener('resize', this.chartResize)
    },
    destroyed() {
    window.removeEventListener('resize', this.chartResize)
    }2. 全局过滤器注册
    2.1 一般情况
    官方注册过滤器的方式:
    export default {
    data () { return {} },
    filters:{
    orderBy (){
    // doSomething
    },
    uppercase () {
    // doSomething
    }
    }
    }但是我们做项目来说,大部分的过滤器是要全局使用的,不会每每用到就在组件里面去写,抽成全局的会更好些。官方注册全局的方式:
    // 注册
    Vue.filter('my-filter', function (value) {
    // 返回处理后的值
    })
    // getter,返回已注册的过滤器
    var myFilter = Vue.filter('my-filter')但是分散写的话不美观,因此可以抽出成单独文件。
    2.2 优化
    我们可以抽出到独立文件,然后使用Object.keys在main.js入口统一注册 /src/common/filters.js
    let dateServer = value => value.replace(/(d{4})(d{2})(d{2})/g, '$1-$2-$3')
    export { dateServer }
    /src/main.js
    import * as custom from './common/filters/custom'
    Object.keys(custom).forEach(key => Vue.filter(key, custom[key]))然后在其他的.vue 文件中就可愉快地使用这些我们定义好的全局过滤器了
    <template>
    <section class="content">
    <p>{{ time | dateServer }}</p> <!-- 2016-01-01 -->
    </section>
    </template>
    <script>
    export default {
    data () {
    return {
    time: 20160101
    }
    }
    }
    </script>3. 全局组件注册
    3.1 一般情况
    需要使用组件的场景:
    <template>
    <BaseInput v-model="searchText" @keydown.enter="search"/>
    <BaseButton @click="search">
    <BaseIcon name="search"/>
    </BaseButton>
    </template>
    <script>
    import BaseButton from './baseButton'
    import BaseIcon from './baseIcon'
    import BaseInput from './baseInput'
    export default {
    components: { BaseButton, BaseIcon, BaseInput }
    }
    </script>我们写了一堆基础UI组件,然后每次我们需要使用这些组件的时候,都得先import,然后声明components,很繁琐,这里可以使用统一注册的形式
    3.2 优化
    我们需要借助一下神器webpack,使用 require.context() 方法来创建自己的 模块 上下文,从而实现自动动态require组件。这个方法需要3个参数:要搜索的文件夹目录、是否还应该搜索它的子目录、以及一个匹配文件的正则表达式。 我们在components文件夹添加一个叫componentRegister.js的文件,在这个文件里借助webpack动态将需要的基础组件统统打包进来。 /src/components/componentRegister.js
    import Vue from 'vue'
    /**
    * 首字母大写
    * @param str 字符串
    * @example heheHaha
    * @return {string} HeheHaha
    */
    function capitalizeFirstLetter(str) {
    return str.charAt(0).toUpperCase() + str.slice(1)
    }
    /**
    * 对符合'xx/xx.vue'组件格式的组件取组件名
    * @param str fileName
    * @example abc/bcd/def/basicTable.vue
    * @return {string} BasicTable
    */
    function validateFileName(str) {
    return /^S+.vue$/.test(str) &&
    str.replace(/^S+/(w+).vue$/, (rs, $1) => capitalizeFirstLetter($1))
    }
    const requireComponent = require.context('./', true, /.vue$/)
    // 找到组件文件夹下以.vue命名的文件,如果文件名为index,那么取组件中的name作为注册的组件名
    requireComponent.keys().forEach(filePath => {
    const componentConfig = requireComponent(filePath)
    const fileName = validateFileName(filePath)
    const componentName = fileName.toLowerCase() === 'index'
    ? capitalizeFirstLetter(componentConfig.default.name)
    : fileName
    Vue.component(componentName, componentConfig.default || componentConfig)
    })这里文件夹结构:
    components
    │ componentRegister.js
    ├─BasicTable
    │ BasicTable.vue
    ├─MultiCondition
    │ index.vue这里对组件名做了判断,如果是index的话就取组件中的name属性处理后作为注册组件名,所以最后注册的组件为: multi-condition 、 basic-table 最后我们在main.js中import 'components/componentRegister.js',然后我们就可以随时随地使用这些基础组件,无需手动引入了~
    4. 不同路由的组件复用
    4.1 场景还原
    当某个场景中vue-router从/post-page/a,跳转到/post-page/b。然后我们惊人的发现,页面跳转后数据竟然没更新?!原因是vue-router"智能地"发现这是同一个组件,然后它就决定要复用这个组件,所以你在created函数里写的方法压根就没执行。通常的解决方案是监听$route的变化来初始化数据,如下:
    data() {
    return {
    loading: false,
    error: null,
    post: null
    }
    },
    watch: {
    '$route': { // 使用watch来监控是否是同一个路由
    handler: 'resetData',
    immediate: true
    }
    },
    methods: {
    resetData() {
    this.loading = false
    this.error = null
    this.post = null
    this.getPost(this.$route.params.id)
    },
    getPost(id){ }
    }4.2 优化
    那要怎么样才能实现这样的效果呢,答案是给 router-view 添加一个不同的key,这样即使是公用组件,只要url变化了,就一定会重新创建这个组件。
    <router-view :key="$route.fullpath"></router-view>还可以在其后加 + +new Date() 时间戳,保证独一无二
    5. 高阶组件
    5.1 一般情况
    // 父组件
    <BaseInput :value="value"
    label="密码"
    placeholder="请填写密码"
    @input="handleInput"
    @focus="handleFocus">
    </BaseInput>
    // 子组件
    <template>
    <label>
    {{ label }}
    <input :value=" value"
    :placeholder="placeholder"
    @focus="$emit('focus', $event)"
    @input="$emit('input', $event.target.value)">
    </label>
    </template>5.2 优化
    1 每一个从父组件传到子组件的props,我们都得在子组件的Props中显式的声明才能使用。这样一来,我们的子组件每次都需要申明一大堆props, 而类似placeholer这种dom原生的property我们其实完全可以使用 $attrs 直接从父传到子,无需声明。方法如下:
    <input :value="value"
    v-bind="$attrs"
    @input="$emit('input', $event.target.value)">$attrs 包含了父作用域中不作为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定,并且可以通过 v-bind="$attrs" 传入内部组件——在创建更高层次的组件时非常有用。
    2 注意到子组件的 @focus="$emit('focus', $event)" 其实什么都没做,只是把event传回给父组件而已,那其实和上面类似,完全没必要显式地申明:
    <input :value="value"
    v-bind="$attrs"
    v-on="listeners"/>
    computed: {
    listeners() {
    return {
    ...this.$listeners,
    input: event =>
    this.$emit('input', event.target.value)
    }
    }
    }$listeners 包含了父作用域中的 (不含 .native 修饰器的)v-on 事件*。它可以通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用。
    需要注意的是,由于我们input并不是BaseInput这个组件的根节点,而默认情况下父作用域的不被认作 props 的特性绑定将会“回退”且作为普通的 HTML 特性应用在子组件的根元素上。所以我们需要设置 inheritAttrs: false ,这些默认行为将会被去掉,以上两点的优化才能成功。
    6. 路由根据开发状态懒加载
    6.1 一般情况
    一般我们在路由中加载组件的时候:
    import Login from '@/views/login.vue'
    export default new Router({
    routes: [{ path: '/login', name: '登陆', component: Login}]
    })当你需要懒加载 lazy-loading 的时候,需要一个个把routes的component改为 () => import('@/views/login.vue') ,甚为麻烦。
    当你的项目页面越来越多之后,在开发环境之中使用 lazy-loading 会变得不太合适,每次更改代码触发热更新都会变得非常的慢。所以建议只在生成环境之中使用路由懒加载功能。
    6.2 优化
    根据Vue的异步组件和Webpack的代码分割功能可以轻松实现组件的懒加载,如:
    const Foo = () => import('./Foo.vue')
    在区分开发环境与生产环境时,可以在路由文件夹下分别新建两个文件: _import_proction.js
    mole.exports = file => () => import('@/views/' + file + '.vue')
    _import_development.js ,这种写法 vue-loader 版本至少v13.0.0以上
    mole.exports = file => require('@/views/' + file + '.vue').default
    而在设置路由的 router/index.js 文件中:
    const _import = require('./_import_' + process.env.NODE_ENV)
    export default new Router({
    routes: [{ path: '/login', name: '登陆', component: _import('login/index') }]
    })这样组件在开发环境下就是非懒加载,生产环境下就是懒加载的了
    7 vue-loader小技巧
    vue-loader 是处理 *.vue 文件的 webpack loader。它本身提供了丰富的 API,有些 API 很实用但很少被人熟知。例如接下来要介绍的 preserveWhitespace 和 transformToRequire
    7.1 用 preserveWhitespace 减少文件体积
    有些时候我们在写模板时不想让元素和元素之间有空格,可能会写成这样:
    <ul>
    <li>1111</li><li>2222</li><li>333</li>
    </ul>当然还有其他方式,比如设置字体的 font-size: 0 ,然后给需要的内容单独设置字体大小,目的是为了去掉元素间的空格。其实我们完全可以通过配置 vue-loader 实现这一需求。
    {
    vue: {
    preserveWhitespace: false
    }
    }它的作用是阻止元素间生成空白内容,在 Vue 模板编译后使用 _v(" ") 表示。如果项目中模板内容多的话,它们还是会占用一些文件体积的。例如 Element 配置该属性后,未压缩情况下文件体积减少了近 30Kb。
    7.2 使用 transformToRequire 再也不用把图片写成变量了
    以前在写 Vue 的时候经常会写到这样的代码:把图片提前 require 传给一个变量再传给组件。
    <template>
    <p>
    <avatar :default-src="DEFAULT_AVATAR"></avatar>
    </p>
    </template>
    <script>
    export default {
    created () {
    this.DEFAULT_AVATAR = require('./assets/default-avatar.png')
    }
    }
    </script>其实通过配置 transformToRequire 后,就可以直接配置,这样vue-loader会把对应的属性自动 require 之后传给组件
    {
    vue: {
    transformToRequire: {
    avatar: ['default-src']
    }
    }
    }于是我们代码就可以简化不少
    <template>
    <p>
    <avatar default-src="./assets/default-avatar.png"></avatar>
    </p>
    </template>在 vue-cli 的 webpack 模板下,默认配置是:
    transformToRequire: {
    video: ['src', 'poster'],
    source: 'src',
    img: 'src',
    image: 'xlink:href'
    }可以举一反三进行一下类似的配置
    vue-loader 还有很多实用的 API 例如最近加入的自定义块,感兴趣的各位可以去文档里找找看。
    8. render 函数
    在某些场景下你可能需要render 渲染函数带来的完全编程能力来解决不太容易解决的问题,特别是要动态选择生成标签和组件类型的场景。
    8.1 动态标签
    1. 一般情况
    比如根据props来生成标签的场景
    <template>
    <p>
    <p v-if="level === 1&

    VueCLI3打包优化--抽离依赖包

    项目开发中,使用了很多依赖包,如 Vue 、路由管理 Vue-router 、状态管理 Vuex 、UI组件库( ElementUI 、 Vant )、图表( echarts )等。打包构建,发现有一些包体积过大,会影响首页加载速度。如下所示:

    从上图的分析包中,可以将以下插件抽离:

    需要删除的依赖包

    VueCLI3自带了 webpack analzer ,可通过如下命令即可生成分析包内容,在 dist/report.html

    更多请查看:
    https://cli.vuejs.org/zh/guide/cli-service.html#vue-cli-service-serve

    减少打包体积、加快打包速度,常规的优化有以下两种:

    按需加载是通过只引用使用的组件来减少体积,这就会有一个问题:如果项目重度依赖第三方插件(如 ElementUI 、 vant ),那么此方案将无法减少打包的体积。

    这里选择CDN的方式,配置流程

    可根据环境变量,仅在线上采取使用CDN,开发环境直接使用npm依赖包即可。

    进行包分离以后,打包结果:

    vue.config.js 的pages为:

    修改如下的地方:

    外部扩展(externals)
    使用webpack的externals来指定echarts无法减少包的大小

    vue-cli利用webpack-bundle-analyzer分析构建产物

    VueCLI3打包优化--抽离依赖包

    项目开发中,使用了很多依赖包,如 Vue 、路由管理 Vue-router 、状态管理 Vuex 、UI组件库( ElementUI 、 Vant )、图表( echarts )等。打包构建,发现有一些包体积过大,会影响首页加载速度。如下所示:

    从上图的分析包中,可以将以下插件抽离:

    需要删除的依赖包

    VueCLI3自带了 webpack analzer ,可通过如下命令即可生成分析包内容,在 dist/report.html

    更多请查看:
    https://cli.vuejs.org/zh/guide/cli-service.html#vue-cli-service-serve

    减少打包体积、加快打包速度,常规的优化有以下两种:

    按需加载是通过只引用使用的组件来减少体积,这就会有一个问题:如果项目重度依赖第三方插件(如 ElementUI 、 vant ),那么此方案将无法减少打包的体积。

    这里选择CDN的方式,配置流程

    可根据环境变量,仅在线上采取使用CDN,开发环境直接使用npm依赖包即可。

    进行包分离以后,打包结果:

    vue.config.js 的pages为:

    修改如下的地方:

    外部扩展(externals)
    使用webpack的externals来指定echarts无法减少包的大小

    vue-cli利用webpack-bundle-analyzer分析构建产物

    怎样使用vue-cli快速搭建项目

    这次给大家带来怎样使用vue-cli快速搭建项目,使用vue-cli快速搭建项目的注意事项有哪些,下面就是实战案例,一起来看一下。

    1. 避坑前言

    其实这次使用vue-cli的过程并不顺利,反复尝试几次都遇到以下这个报错:

    创建vue-cli工程项目时的报错

    在网上查了很多资料才发现原来是node版本过低的问题,虽然没有找到官方对这个“过低”问题的解释,但是根据国友的经验之谈,应该是至少使用node6,我将node4更新至node8之后确实没有报错了,顺利搭建。相关答疑帖:https://github.com/vuejs/vue-cli/issues/618

    确认node与npm的版本

    将这个放在最前面说是希望大家在搭建前,应该先确保将node更新至6以上,这样能少走一些弯路。下面开始正式介绍整个构建过程。

    2. 使用 vue-cli 搭建项目

    下面整个过程是基于已经安装node.js和cnpm的基础上,node.js如何安装就不在这里详说了。如何全局化安装cnpm,这里简单提一下:

    npm install cnpm -g --registry=https://registry.npm.taobao.org其实对于安装vue-cli,使用npm命令和cnpm命令都是可以的,个人觉得使用npm安装的比较慢,而且很可能会因为网络问题而出错,所以还是觉得使用cnpm稳一点。

    (1)全局安装 vue-cli ,在命令提示窗口执行:

    cnpm install -g vue-cli

    安装vue-cli

    出现以上提示表示vue-cli正常安装成功,可以正式创建vue-cli工程项目了。

    (2)安装vue-cli成功后,通过cd命令进入你想放置项目的文件夹,在命令提示窗口执行创建vue-cli工程项目的命令:

    vue init webpack

    创建vue-cli工程项目

    确认创建项目后,后续还需输入一下项目名称、项目描述、作者、打包方式、是否使用ESLint规范代码等等,详见上图。安装顺利执行后会,生成如下文件目录:

    生成文件目录

    (3)生成文件目录后,使用 cnpm 安装依赖:

    cnpm install

    安装依赖

    (4)最后需要执行命令: npm run dev 来启动项目,启动完成后会自动弹出默认网页:

    启动项目

    启动项目

    默认网页

    到这一步,就算成功利用vue-cli搭建一个vue项目了,撒花 ~

    3.目录结构及其对应作用

    通过vue-cli搭建一个vue项目,会自动生成一系列文件,而这些文件具体是怎样的结构、文件对应起什么作用,可以看看下面的解释:

    ├── build/ # webpack 编译任务配置文件: 开发环境与生产环境

    │ └── ...

    ├── config/

    │ ├── index.js # 项目核心配置

    │ └── ...

    ├ ── node_mole/ #项目中安装的依赖模块

    ── src/

    │ ├── main.js # 程序入口文件

    │ ├── App.vue # 程序入口vue组件

    │ ├── components/ # 组件

    │ │ └── ...

    │ └── assets/ # 资源文件夹,一般放一些静态资源文件

    │ └── ...

    ├── static/ # 纯静态资源 (直接拷贝到dist/static/里面)

    ├── test/

    │ └── unit/ # 单元测试

    │ │ ├── specs/ # 测试规范

    │ │ ├── index.js # 测试入口文件

    │ │ └── karma.conf.js # 测试运行配置文件

    │ └── e2e/ # 端到端测试

    │ │ ├── specs/ # 测试规范

    │ │ ├── custom-assertions/ # 端到端测试自定义断言

    │ │ ├── runner.js # 运行测试的脚本

    │ │ └── nightwatch.conf.js # 运行测试的配置文件

    ├── .babelrc # babel 配置文件

    ├── .editorconfig # 编辑配置文件

    ├── .gitignore # 用来过滤一些版本控制的文件,比如node_moles文件夹

    ├── index.html # index.html 入口模板文件

    └── package.json # 项目文件,记载着一些命令和依赖还有简要的项目描述信息

    └── README.md #介绍自己这个项目的,可参照github上star多的项目。

    build/相信看了本文案例你已经掌握了方法,更多精彩请关注Gxl网其它相关文章!

    推荐阅读:

    JS实现最简单的查找、排序、去重算法

    如何使用jQuery实现获取随机颜色

    vue中如何取字符串“20%”中的20

    vue中如何取字符串“20%”中的20方法如下:

    取某一段字符,同样修改计算属性,改成return this.ipaddr.substr(2,5)。意思为从第二个字符开始(应该说是第三个,因为在数组中以0开始),截取长度为5的一串字符。截取某一段字符,修改计算属性,改成return this.ipaddr.substring(2,6)意思为从第二个字符开始(应该说是第三个,因为在数组中以0开始)到第六个字符结束。

    站点网还为您提供以下相关内容希望对您有帮助:

    怎么提速优化vue-cli的代码

    通过借助插件babel-plugin-import 可以实现按需加载组件,减少文件体积,只需要修改 .babelrc 文件npm install babel-plugin-import --save-dev// .babelrc{ "plugins": [["import", { "libraryName": "iview", "libraryD...

    如何优化Vue

    │ index.vue这里对组件名做了判断,如果是index的话就取组件中的name属性处理后作为注册组件名,所以最后注册的组件为: multi-condition 、 basic-table 最后我们在main.js中import 'components/componentRegister.js',然后我们就可以随时随...

    怎样使用vue-cli快速搭建项目

    (1)全局安装 vue-cli ,在命令提示窗口执行:cnpm install -g vue-cli安装vue-cli出现以上提示表示vue-cli正常安装成功,可以正式创建vue-cli工程项目了。(2)安装vue-cli成功后,通过cd命令进入你想放置项目的文件夹,...

    vue的组件与框架结构如何选用

    1.vue-cli: https://github.com/vuejs/vue-cli 脚手架工具,当我们选择vue作为我们的开发技术栈以后,就要开始为我们的项目搭建目录及开发的环境。安装好node以后,通过以后命令进行安装 npm install -g vue-cli 将vue-cli安装到全局环...

    vue怎么运行

    1、npm install#160#160或cnpm install 4将Vue build后生成的dist文件夹下的所有文件复制到express项目的publick文件夹下面,然后运行#160#160npm start#160来启动express项目5打开浏览器,输入localhost3。2、1首先在IDEA中...

    vue前端面试题有哪些呢?

    21、请说出vue.cli项目中src目录每个文件夹和文件的用法?答:assets文件夹是放静态资源;components是放组件;router是定义路由相关的配置;view视图;app.vue是一个应用主组件;main.js是入口文件22、vue.cli中怎样使用自定义的组件?有遇到...

    47道基础的VueJS面试题(附答案)

    19、请说出vue.cli项目的src目录中每个文件夹和文件的用法。 assets文件夹存放静态资源;components存放组件;router定义路由相关的配置;view是视图;app. vue是一个应用主组件;main.js是入口文件。 20、在Vue.cli中怎样使用自定义组件?

    vue高德地图 如何一次添加多个点标记到地图实例?

    首先你需要提交你的公司的资料信息,地址信息 ,公司名称 以及电话信息,门脸照片给官方,提交给官方后,他们会审核的,一般都是 1-7个工作日审核 审核通过后1-3天时间展现 如果发现地图有错误,可以进行纠错处理。

    请各位英语达人帮我翻译一下软件工程师简历中的 项目经验 不胜感激...

    3. 企业客户关系管理系统  项目介绍:本项目旨在“以客户为中心,以市场为导向”的企业经营管理模式,通过集中管理客户信息,并在市场部、销售部、服务部等间共享客户数据,从而实现企业市场营销、销售管理、客户服务和支持等经营流程信息...

    使用Vue时有哪些小技巧

    3.2 优化我们需要借助一下神器webpack,使用 require.context() 方法来创建自己的 模块 上下文,从而实现自动动态require组件。这个方法需要3个参数:要搜索的文件夹目录、是否还应该搜索它的子目录、以及一个匹配文件的正则表达式。 我们在...

    本文如未解决您的问题请添加抖音号:51dongshi(抖音搜索懂视),直接咨询即可。

    精彩推荐

    更多阅读

    Top