关闭搜索(ESC)
搜索标签:

es6+webpack+vue项目实践

2018-01-24 浏览:7630 标签: vue webpack

es6 + webpack + vue1.0

最近开发一个铜盘功能,用了以上的技术栈开发。有一些心得可以记录下来。包括写的模块的经验。

构建

后台是用java实现,使用velocity模板。目录结构

---webapp
|-----resource
|--------init            // 初始js文件
|--------src
|-----------business     // 业务vue组件
|-----------components   // 基础vue组件
|--------stylesheets
|-----------style.css    // 基础css样式
|-----WEB-INF
|--------view               // velocity
|-----------include         // 公用velocity模板
|-----------xxx.vm          // 业务velocity

以上是基础目录结构,现在开始构建前端环境。

配置npm

(以下配置行为的前提是该项目没有配置过)

执行 npm init 配置,按要求填写配置内容。生成pakcage.json。

安装库,包括:

(请不要复制)

vue库:
npm install vue, vue-hot-reload-api, vue-html-loader, vue-resource, vue-router, vue-style-loader

webpack库:
npm install webpack, webpack-dev-server

css库:
npm install style-loader, stylus, stylus-loader, css-loader

gulp库:
npm install gulp

es6支持库:
npm install babel-core, babel-loader, babel-plugin-transform-runtime, babel-preset-es2015, babel-runtime, es6-promise

jquery库:
npm install jquery

配置webpack

var vue = require('vue-loader');
var webpack = require('webpack');
var path = require('path');

var paths = {
    src: './resources/src/',
    dist: './resources/dist/'
};

module.exports = {
    entry: {
        'fileList': paths.src + 'business/fileList/app.js',
        'uploadFile': paths.src + 'business/uploadFile/app.js'
        // 'interface': paths.src + 'javascripts/interface.js'
    },
    output: {
        path: paths.dist + 'business',
        publicPath: paths.dist + 'business',
        filename: '[name].js'
    },
    resolve: {
        extensions: ['', '.js', '.vue', '.styl'],
        alias: {
              'src': path.resolve(__dirname, './resources')
        }
      },
      resolveLoader: {
        root: path.join(__dirname, 'node_modules'),
      },
    module: {
        loaders: [{
            test: /\.vue$/,
            loader: 'vue'
        }, {
            test: /\.js$/,
            exclude: /node_modules|vue\/dist|vue-router\/|vue-loader\/|vue-hot-reload-api\//,
            loader: 'babel'
        }, {
            // edit this for additional asset file types
            test: /\.(png|jpg|gif)$/,
            loader: 'url',
            query: {
                // inline files smaller then 10kb as base64 dataURL
                limit: 10000,
                // fallback to file-loader with this naming scheme
                name: '[name].[ext]?[hash]'
            }
        }, {
            test: /\.styl$/,
            loader: 'style-loader!css-loader!stylus-loader'
        }]
    },
    babel: {
        presets: ['es2015'],
        plugins: ['transform-runtime']
    },
    // 如果要全部都用jQuery,就用插件的方法加载jQuery,代码在下面👇
    // plugins: [
 //        new webpack.ProvidePlugin({
 //            $: "jquery",
 //            jQuery: "jquery",
 //            "window.jQuery": "jquery"
 //        })
 //    ]
};

webpack的使用方法可以可以个分享会了,下次讲。

webpack其实就是用各种loader来对库的加载,合并。这边主要用到vue,babel和css以及css的扩展库。

vue组件

举个例子

<template>
    <div>
        <div id="{{chartData.id}}" class="flot-chart-pie"></div>
        <div class="flc-pie hidden-xs"></div>
    </div>
</template>

<script>

    export default {
        props: {
            chartData: {
                type: Object,
                require: true
            }
        },

        ready () {
            this.showPie()
        },

        created () {
            let self = this
            self.$watch('chartData', function(val) {
                self.showPie()
            })
        },

        data () {
            return {

            }
        },

        methods: {
            showPie () {
                let self = this;
                $.plot('#'+self.chartData.id, self.chartData.dataList, {
                    series: {
                        pie: {
                            show: true,
                            radius: 1,
                            stroke: { 
                                width: 2,
                            },
                            label: {
                                show: true,
                                radius: 2/3,
                                formatter: self.labelFormatter,
                                threshold: 0.1
                            }
                        },
                    },
                    legend: {
                        container: '.flc-pie',
                        backgroundOpacity: 0.5,
                        noColumns: 0,
                        backgroundColor: "white",
                        lineWidth: 0
                    },
                    grid: {
                        hoverable: true,
                        clickable: true
                    },
                    tooltip: true,
                    tooltipOpts: {
                        content: "%p.0%, %s", // show percentages, rounding to 2 decimal places
                        shifts: {
                            x: 20,
                            y: 0
                        },
                        defaultTheme: false,
                        cssClass: 'flot-tooltip'
                    }
                });
            },
            labelFormatter(label, series) {
                return "<div style='font-size:8pt; text-align:center; padding:2px; color:white;'>" + label + "<br/>" + Math.round(series.percent) + "%</div>";
            }
        }
    }
</script>

vue组件在一个.vue里包括所有的css,template和js文件。一个好的组件,有以下几点要求

prop 允许外部环境传递数据给组件;

事件 允许组件触发外部环境的 action;

slot 允许外部环境插入内容到组件的视图结构内。

当使用这个组件的时候,只要:

js:

import pieChart from '../../components/chart/pieChart'
export default {
    components: {
        'v-chart-pie': pieChart,
    }
}

template:

<v-chart-pie></v-chart-pie>

以上是组件的做法,下面讲的前端思考才是最重要的。

前端更优化

在一个项目里,在angular.js讲的都是单页面的设计。但是对于大项目,单页面往往是复杂度就会提升,所以希望是一个项目里有多个单页面的设计。

举个例子:

/list /list/#!/one /list/#!/show

/upload /upload/#!/selectfile /upload/#!/begin

所以需要设计多个单页面,以及不同单页面的公用部分:

设计demo:

|---business
|------baseView
|----------main.vue             // 主框架
|----------searchView.vue       // 搜索组件
|------fileList                 // 文件列表单页面
|----------views
|-------------listView.vue      // 列表
|----------app.js
|----------router.js            // 路由地址配置
|------uploadFile               // 上传列表单页面
|----------views
|-------------uploadView.vue    // 上传
|----------app.js
|----------router.js

app.js配置vue:

import Vue from 'vue'
import VueRouter from 'vue-router'
import VueResource from 'vue-resource'
import routerConfig from './router'
import app from '../baseView/main'

// Router
Vue.use(VueRouter)

const router = new VueRouter({
    hashbang: true,
    history: false,
    saveScrollPosition: true,
    suppressTransitionError: true
})

routerConfig(router)

// Resource
Vue.use(VueResource)

Vue.http.options.root = '/'
Vue.http.options.emulateJSON = true

// Directive

router.start(app, '#app')

window.router = router

router.js配置路由地址

import ListView from './views/listView'
import SearchView from '../baseView/searchView'

export default function(router) {
    router.map({
        '/list': {
            name: 'list',
            component: ListView
        },
        '/search': {
            name: 'search',
            component: SearchView
        }
    })

    router.redirect({
        '/': '/list'
    })

    router.beforeEach(function ({to, from, next}) {
        let toPath = to.path
        let fromPath = from.path
        console.log('to: ' + toPath + ' from: ' + fromPath)
        if (toPath.replace(/[^/]/g, '').length > 1) {
              router.app.isIndex = false
        }
        else {
              router.app.isIndex = true
        }
        next()
      })

      router.afterEach(function ({to}) {
        console.log(`成功浏览到: ${to.path}`)
        // $.refreshScroller()
      })
}

现在关键的是,如何实现不同路由间路怪的跳转。因为在/list 和/upload下的hash跳转,如果公用同一个组件,比如导航组件,路由是不一样的,所以,可以如下设置:

    created () {
        this.options.navItems = [{
            label: '首页',
            rootPath: '/#!',
            path: '/list',
            active: '',
            isOut: false
        }, {
            label: '上传',
            rootPath: '/uploadindex#!',
            path: '/upload',
            active: '',
            isOut: false
        }, {
            label: '接入指南',
            rootPath: '/file/help.html',
            path: '',
            active: '',
            isOut: true
        }];

        this.opPath()
    },

    methods: {
        handleNav (rp) {
            let self = this
            for(let i=0; i<self.options.navItems.length; i++) {
                let thisNavItem = self.options.navItems[i]
                if(thisNavItem.rootPath != rp) {
                    thisNavItem.isOut = true
                    thisNavItem.active = ""
                } else {
                    thisNavItem.isOut = false
                    thisNavItem.active = "active"
                }
            }
        },

        opPath () {
            let self = this
            let nowRootPath = window.location.pathname

            switch(nowRootPath) {
                case '/':
                    self.handleNav('/#!')
                    break;
                case '/uploadindex':
                    self.handleNav('/uploadindex#!')
                    break;
                default:
                    break;
            }
        }
    }

以上就可以实现跳转了。跪求更好的方法。

添加评论