vue-cli 实战

  最近,MVC、MVVM框架越发流行,当然必不可少的,我也趁着最近工作量小,学习了一个多星期的vue.js 2.0版本, 改造了一个购票项目,借此分享下学习心得,希望对一部分人有所帮助,当然,有任何不对的地方还望各路大神指出批评,谢谢啦!

  vue.js是一种流行的mvvm模式的框架,其核心思想是 数据驱动 和 组件化,相比于Angular.js , vue.js提供了更加简洁,更易理解的API, 使我们能够快速上手开发。

1、vue-cli 安装(默认你已有node.js环境)

npm install vue-cli -g

2、创建一个以webpack为模板的项目(一直yes就会有单元测试,eslint代码检查等,我的是默认vue init webpack后,一直enter)--我的根目录为m86xq

vue init webpacknpm installnpm install vuex vue-resource mint-ui --save (本项目用到的依赖,vuex管理应用程序的状态;vue-resource为vue的ajax库,现在推荐使用axios;mint-ui为饿了么的移动端ui框架)npm install sass-loader node-sass --save-dev (vue文件用到sass,需要的依赖)

3、运行项目

npm run dev

4、浏览器自动打开后可以看到vue.js的界面,则运行成功

5、目录结构(由于项目是我做好了一部分的,所以有些文件是你们没有的,后面会说到)

src/store目录下的是vuex的文件;

src/sass目录为各个组件的sass样式以及定义的变量,mixins等

router目录为项目路由设置

static/fonts为移动端的字体图标

static/css为页面初始化css(reset.css),我这是通过index.html直接写在head里

data.json是自定义的假数据

6、main.js

import Vue from ‘vue‘
import App from ‘./App‘
import VueResource from ‘vue-resource‘
import router from ‘./router‘
import store from ‘./store‘

import MintUi from ‘mint-ui‘
import ‘mint-ui/lib/style.css‘
import ‘../static/css/font-awesome.min.css‘

Vue.use(MintUi)
Vue.use(VueResource)
/* eslint-disable no-new */
new Vue({
  router,
  store,
  render: h => h(App)
}).$mount(‘#app‘)

a、import为es6的语法,将模块导入进来,在main.js导入的,在全局都能使用

b、外部的一些库,例如mint-ui, vue-resource导入进来后,都需要通过Vue.use()使用

c、创建一个vue实例,挂载路由,数据启动(还不能运行,还要App.vue)

7、router/index.js

import Vue from ‘vue‘
import Router from ‘vue-router‘

Vue.use(Router)
import Index from ‘components/index‘
import Home from ‘components/home‘
import Order from ‘components/order‘
export default new Router({
  routes: [
      {
          path: ‘/index‘,
          component: Index,
          children: [
              {
                path: ‘‘,
                component: Home,
                meta: { hideHeader: true }
              },
              {
                path: ‘order‘,
                component: Order,
                meta: { hideHeader: false }
              }
          ]
      },
      {
          path: ‘/‘,
          redirect: ‘/index‘
      }
  ]
})

8、App.vue

<template>
  <div id="app">
      <v-menu></v-menu>
    <router-view></router-view>
  </div>
</template>

<script>
import menu from ‘components/menu‘
export default {
    components: {
        vMenu: menu
    }
}
</script>
<style lang="scss">
    .menu {
        transition: all 0.2s cubic-bezier(0.55, 0, 0.1, 1);
    }
    .slide-left-enter, .slide-right-leave-active {
       opacity: 0;
       -webkit-transform: translate(30px, 0);
       transform: translate(30px, 0);
    }
    .slide-left-leave-active, .slide-right-enter {
       opacity: 0;
       -webkit-transform: translate(-30px, 0);
       transform: translate(-30px, 0);
    }
</style>

9、index.vue(作为滑动外层)

<template>
  <transition :name="transitionName">
    <router-view class="view"></router-view>
  </transition>
</template>
<script>
export default {
  name: ‘index‘,
  data () {
    return {
      transitionName: ‘slide-left‘
    }
  },
  watch: {
    ‘$route‘: function (to, from) {
      const toDepth = to.path.split(‘/‘).length
      const fromDepth = from.path.split(‘/‘).length
      this.transitionName = toDepth < fromDepth ? ‘slide-right‘ : ‘slide-left‘
    }
  }
}
</script>
<style lang="scss" scoped>
  .view{
    transition: all .2s ease;
  }
</style>

10、home.vue

<template>
    <div class="home">
        <mt-header>
          <router-link to="/" slot="left" class="logo"></router-link>
        </mt-header>
        <!-- icon -->
        <ul class="service_layer">
            <li v-for="(item, index) in service_a" :class="item.cln">
                <a :href=‘item.link‘ @click="showIndex(index)">
                    <div class="icon"><img :src="item.imgUrl"></div>
                    <p class="service_txt">{{ item.name }}</p>
                </a>
            </li>
        </ul>
        <!-- 广告 -->
        <div class="adv_layer" :class="{ ‘hide‘: !advStatus }">
            <span class="fa fa-close" @click="advClose"></span>
            <a class="adv_inner" href="http://mall.866xq.com/g_43">
                <img src="http://img.mall.8666.com/wxshop20170213/5ac796e10c.jpg">
                <p class="adv_title">
                    <span class="text">情人节尊享——买女士养颜谷花香送58元999大罐甘肃特级玫瑰
                          <small>(小区特供)</small>
                      </span>
                      <span class="adv_btn">马上抢购</span>
                </p>
            </a>
        </div>
        <div class="bar-title">中海誉城</div>
        <div class="residents_layer">
          <span class="residents_tit"><i></i>小区已入住&nbsp;6398&nbsp;人</span>
          <span class="share_btn">马上邀请邻居入住</span>
      </div>
      <!-- 选择时间与方向 -->
      <div class="line-type">
        <span>时间</span>
        <mt-button type="primary" size="small" :plain="lineDateType != ‘workDay‘" @click.native="lineDateTypeHandle(‘workDay‘)">工作日</mt-button>
        <mt-button type="primary" size="small" :plain="lineDateType != ‘weekend‘" @click.native="lineDateTypeHandle(‘weekend‘)">周末</mt-button>
    </div>
    <div class="line-type">
        <span>方向</span>
        <mt-button type="primary" size="small" :plain="lineDirection !=‘go‘" @click.native="lineDirectionHandle(‘go‘)">出门</mt-button>
        <mt-button type="primary" size="small" :plain="lineDirection !=‘back‘" @click.native="lineDirectionHandle(‘back‘)">回家</mt-button>
    </div>
    <ul class="route-list">
        <li v-for="item in routeList">
            <div class="title">{{ item.title }}</div>

            <div class="content" v-for="con in item.items">
                <div class="route-name">{{ con.name }}</div>
                <div class="route">
                    <span class="beginPoint">{{ con.beginPoint }}</span> → <span class="endPoint">{{con.endPoint}}</span>
                </div>
                <div class="select-time">
            <mt-button type="primary" size="small" plain  v-for="itemTime in con.time"
                            @click.native="orderTo(con.name, itemTime)"
            >
                {{ itemTime }}
            </mt-button>
              </div>
              <div class="price"><span>¥</span>{{ con.price }}</div>
            </div>
        </li>
    </ul>
    <footer>
        <p>?2016 xq.xxxx.com</p>
        <p>我司诚征PHP程序员,详情联系[email protected]</p>
    </footer>
    </div>
</template>
<script>
import { mapGetters } from ‘vuex‘

export default {
    name: ‘Home‘,
    data () {
        return {
            service_a: [
                { cln: ‘serviceLi1‘, link: ‘/#/index‘, name: ‘88巴士‘, imgUrl: ‘http://css.xxxx.com/xq/images/bus_w.png‘ },
                { cln: ‘serviceLi2‘, link: ‘/#/my/ticket‘, name: ‘我的车票‘, imgUrl: ‘http://css.xxxx.com/xq/images/wodechepiao_w.png‘ },
                { cln: ‘serviceLi3‘, link: ‘/#/my‘, name: ‘我‘, imgUrl: ‘http://css.xxxx.com/xq/images/usericon_w.png‘ }
            ],
            routeList: []
        }
    },
    computed: {
        ...mapGetters([‘advStatus‘, ‘lineDateType‘, ‘lineDirection‘])
    },
    created () {
        this.$http.get(‘../../static/data.json‘, {foo: ‘bar‘}).then(response => {
            response = response.body
            this.routeList = response.routeList
        })
    },
    methods: {
        advClose () {
            this.$store.dispatch(‘advClose‘)
        },
        lineDateTypeHandle (value) {
            this.$store.dispatch(‘lineDateTypeSwitch‘, value)
        },
        lineDirectionHandle (value) {
            this.$store.dispatch(‘lineDirectionSwitch‘, value)
        },
        orderTo (id, time) {
            console.log(‘id: ‘ + id + ‘time:‘ + time)
            console.log(this.$store.state.order.lineDateType + ‘ ‘ + this.$store.state.order.lineDirection)
            this.$router.push({ path: ‘/index/order‘ })
        }
    }
}
</script>
<style lang=‘scss‘ scoped>
@import ‘../sass/home‘;
</style>

11、menu.vue

<template>
    <transition :name="transitionName">
          <div class="menu" v-if="isMenu">
              <div class="inner">
                  <a href="" class="avatar">
                      <img :src="user.image">
                      <div class="name">{{ user.name }}</div>
                  </a>
                  <mt-cell title="886巴士" to="/index" is-link v-if="nowRoute!=‘/index‘"><i slot="icon" class=‘fa fa-home‘></i></mt-cell>
          <mt-cell title="我的车票" to="/my/ticket" is-link><i slot="icon" class=‘fa fa-ticket‘></i></mt-cell>
          <mt-cell title="我的优惠券" to="/my/coupons" is-link><i slot="icon" class=‘fa fa-gift‘></i></mt-cell>
          <mt-cell title="个人中心" to="/my" is-link v-if="nowRoute!=‘/my‘"><i slot="icon" class=‘fa fa-gear‘></i></mt-cell>
          <mt-cell title="所有小区" to="/" is-link><i slot="icon" class=‘fa fa-map-signs‘></i></mt-cell>
              </div>
              <div class="spaceMask" @click="menuToggle"></div>
          </div>
      </transition>
</template>
<script>
    export default {
        data () {
            return {
                isMenu: true,
                transitionName: ‘‘,
                user: {
            name: ‘曾小闲‘,
            image: ‘http://wx.qlogo.cn/mmopen/C1SzxNakKfYbL3cb4FOlXWv4WZwd3jc7sevqQx4Ku89ibxmGfVGd9ophyu6dhG6jtPzWvj9VDTHP7YxjaToJ8dscB9icx026X8/0‘,
            phone: ‘135******80‘,
            credit: 50
          },
          nowRoute: this.$route.path
            }
        },
        methods: {
            menuToggle () {
                this.isMenu = !this.isMenu
                this.transitionName = this.isMenu ? ‘slide-left‘ : ‘slide-right‘
            }
        }
    }
</script>
<style lang="scss" scoped>
    @import ‘../sass/menu‘
</style>

12、order.vue

<template>
    <div class="order-wrap">
        <mt-header fixed title="购票">
          <router-link to="/" slot="left">
            <mt-button icon="back">返回</mt-button>
          </router-link>
        </mt-header>
        <div class="overflow-scroll">
            <div class="lineInfo-box">
                <div class="carIndicator">上车点<br>指示图</div>
                <!-- 单个起点/终点info块 -->
                <div class="info-con">
                    <div class="title start">起点:岭南雅筑/中海誉城</div>
                    <ul class="routeDetail">
                        <li><span class="time">07:00</span><span class="routeInfo">[岭南雅筑]正门路边</span></li>
                        <li><span class="time"></span><span class="routeInfo">请在途经点到达时间前候车,仅供参考.)</span></li>
                        <li><span class="time">07:03</span><span class="routeInfo">[金色梦想]中海公寓公交站(靠中海别墅那边)</span></li>
                        <li><span class="time">07:05</span><span class="routeInfo">[中海誉城]洋城一路公交站(南苑扶梯大门对面)</span></li>
                    </ul>
                </div>
                <!-- 单个起点/终点info块 -->
                <div class="info-con">
                    <div class="title end">终点:岭南雅筑/中海誉城</div>
                    <ul class="routeDetail">
                        <li><span class="time">07:00</span><span class="routeInfo">[岭南雅筑]正门路边</span></li>
                        <li><span class="time"></span><span class="routeInfo">请在途经点到达时间前候车,仅供参考.)</span></li>
                        <li><span class="time">07:03</span><span class="routeInfo">[金色梦想]中海公寓公交站(靠中海别墅那边)</span></li>
                        <li><span class="time">07:05</span><span class="routeInfo">[中海誉城]洋城一路公交站(南苑扶梯大门对面)</span></li>
                    </ul>
                </div>
                <ul class="carRules" v-for="item in rules">
                    <li>{{item}}</li>
                </ul>
                <div class="ticket_price">
          <span class="price">¥14.00</span><span class="unit">/座</span>
        </div>
            </div>
            <div class="warning lineInfo-box">

                <p>如有更多疑问请联系<i class="fa fa-phone"></i><a href="tel:137-1936-7437">137-1936-7437</a></p>
                <p>(班车正常情况准点从发车点发车,不接受申请让班车等待乘客,请提前候车。)</p>
            </div>
        </div>
        <footer>
            <div class="rule-confirm">
                <label class="checkbox">

                    <input type="checkbox" v-model="agreement">
                    <i></i>
                    我已阅读
                </label>
                <a class="a_lnk" href="#/index/gtxz">购票退票规则</a>
            </div>
            <mt-button type="primary" size="large" :disabled="buttonDisabled" @click.native="orderPop">购票&nbsp;&nbsp;¥14.00/座</mt-button>
        </footer>
    </div>
</template>
<script>
import { Indicator } from ‘mint-ui‘
export default {
    data () {
    return {
      agreement: true,
      popupLoading: false,
      rules: [
          ‘* 占座即需要购票,不设站票,儿童购票票价不变;‘,
        ‘* 车型、车牌号请购票后到【我的车票】页面查看;‘,
        ‘* 请提前5分钟候车,认准车牌号上车,并对号入座;‘,
        ‘* 发车前20分钟不可退票,如因个人原因误车恕不退票;‘,
        ‘* 如需更改班次请尽早退票或者改签,把座位释放给其他乘客购买;‘,
        ‘* 严抓逃票,非上车前购票请统一到首页底部补票窗口补票。‘
      ]
    }
  },
    computed: {
        buttonDisabled: function () {
       return !this.agreement || this.popupLoading
    }
    },
    methods: {
        orderPop () {
            Indicator.open({
                spinnerType: ‘fading-circle‘
            })
        }
    }
}
</script>
<style lang="scss" scoped>
@import ‘../sass/order‘;
</style>

13、vuex的使用

目录结构:

index.js为集中所有状态导出去,其中state为数据源,getters为过滤数据源(相当于vue里边的computed),mutations为定义的方法,actions为提交mutations的方法(即调用mutations里的函数)

import Vue from ‘vue‘
import Vuex from ‘vuex‘

import getters from ‘./getters‘
import mutations from ‘./mutations‘
import actions from ‘./actions‘

import adv from ‘./modules/adv‘
import order from ‘./modules/order‘

Vue.use(Vuex)

export default new Vuex.Store({
    modules: {
        adv,
        order
    },
    getters,
    mutations,
    actions
})

mutation-types.js为定义的方法名

export const ADV_CLOSE = ‘ADV_CLOSE‘             // 关闭广告
export const LINE_DATE_TYPE = ‘LINE_DATE_TYPE‘   // 路线时间
export const LINE_DIRECTION = ‘LINE_DIRECTION‘   // 路线方向

modules/adv.js为广告相关代码

import * as types from ‘../mutation-types‘
const state = {
    adv: {
        data: ‘‘,
        status: true
    }
}

const getters = {
    advStatus: state => state.adv.status
}

const mutations = {
    [types.ADV_CLOSE] (state) {
        state.adv.status = false
    }
}

const actions = {
    advClose ({commit}) {
        commit(types.ADV_CLOSE)
    }
}

export default {
    state,
    getters,
    mutations,
    actions
}

modules/order.js为选择车票的相关操作

import * as types from ‘../mutation-types‘
const state = {
    lineDateType: ‘workDay‘,
    lineDirection: ‘go‘ //go表示去   back表示回程
}

const getters = {
    lineDateType: state => state.lineDateType,
    lineDirection: state => state.lineDirection
}

const mutations = {
    [types.LINE_DATE_TYPE] (state, value) {
        state.lineDateType = value === ‘workDay‘ ? ‘workDay‘ : ‘weekend‘
    },
    [types.LINE_DIRECTION] (state, value) {
        state.lineDirection = value === ‘go‘ ? ‘go‘ : ‘back‘
    }
}

const actions = {
    lineDateTypeSwitch ({ commit }, value) {
        commit(types.LINE_DATE_TYPE, value)
    },
    lineDirectionSwitch ({ commit }, value) {
        commit(types.LINE_DIRECTION, value)
    }
}

export default {
    state,
    getters,
    mutations,
    actions
}

总结:

  1、主要难点在于vuex状态管理,对于首次运用mvvm的我来说,这是比较难理解的。现在看看其实很简单,就是把一些全局需要用到的,有影响的数据提取到vuex里边集中管理,这样当在a处修改数据时,b处能及时响应更新

  2、由于vue.js是组件化,数据驱动思想,所以在任何时候,需要修改页面内容或者结构时,首先想到的应该是通过操作数据从而达到结构变化的目的。多处用到的可以提取出来作为组件复用

  3、由于这边用到了vue-cli + webpack,所以在写scss时,浏览器兼容问题构建工具来处理

  

时间: 2024-08-07 04:33:30

vue-cli 实战的相关文章

Vue CLI 3开发中屏蔽烦人的EsLint错误

问题 Vue开发中,特别是当你阅读分析别人的其中早期版本的Vue代码时往往会遭遇到满屏幕的烦人的EsLint错误.有关EsLint这个工具的作用不再赘述.查阅网上参考文档,大多是针对早起版本Vue CLI工具项目的,在我最新使用的Vue CLI 3生成的工程中根本不起作用.无奈之下,认真学习了Vue CLI 3官方文档,终于找到最佳答案. 办法 Vue这个前端框架相对于React和Angular,入门会非常快.但是,到了中后期实战阶段仍然有许多工程实际问题需要我们一块一块地攻克.Vue CLI这

使用vue cli开发项目中遇到的坑

一.部署文件 使用vue cli 开发项目,执行npm run build命令生成dist静态文件,将dist文件包放到服务器中即可. 刚接触webpack,不知道怎么部署前端文件,原以为需要将app文件上传,在 inux上安装node,以及npm install 一系列的包,捣鼓了很久,发现只需要执行 npm run build 将源码打包成一个静态文        文件即可,上传静态文件dist,将 controller指向index.html. 二.跨域问题 实行前后端分离,使用vue i

vue.js实战学习——指令与事件

注:此内容摘抄自:梁灏的<Vue.js实战> 1.指令是Vue.js模版中最常用的一项功能,它带有前缀 v- ,比如:v-if , v-html ,v-pre 等.指令的主要职责就是当其表达式的值改变时,相应的将某些行为应用到DOM上. <div class="app1"> <p v-if="show">哈喽?</p> </div> var app=new Vue({ el:'.app1', data:{

vue.js实战学习——v-bind 及class与 style绑定

注:此内容摘抄自:梁灏的<Vue.js实战> 注:记得要引入vue.js才能运行哦,文章中贴出的代码直接复制是不行的,html css js 都放在了一起,而且也没有引用vue.js. DOM元素经常会动态的绑定一些class类名或style样式. 1.了解v-bind指令 它的主要用法是动态更新HTML元素上的属性. 在数据绑定中,最常见的两个需求就是元素的样式名称class和内联样式style的动态绑定,他们也是HTML的属性,因此可以使用v-bind指令.我们只需要用v-bind计算出表

vue.js实战学习——内置指令(一)

注:此内容摘抄自:梁灏的<Vue.js实战> 注:记得要引入vue.js才能运行哦,文章中贴出的代码直接复制是不行的,html css js 都放在了一起,而且也没有引用vue.js.   1.v-cloak v-cloak不需要表达式,它会在Vue实例结束编译时从绑定的HTML元素上移除,经常和CSS的display:none: 配合使用. <div class="app1" v-cloak> {{message}} </div> var app1

如何使用@vue/cli 3.0在npm上创建,发布和使用你自己的Vue.js组件库

译者按: 你可能npm人家的包过成千上万次,但你是否有创建,发布和使用过自己的npm包? 原文: How to create, publish and use your own VueJS Component library on NPM using @vue/cli 3.0 译者: Fundebug 为了保证可读性,本文采用意译而非直译.另外,本文版权归原作者所有,翻译仅用于学习. 尽管我已经在工作上用了Vue.js一段时间,但我从不需要在npm上发布组件.但最近发现在不同的项目重写组件是件非

vue.cli脚手架初次使用图文教程

vue.cli脚手架初次使用图文教程 我之前的环境是安装了node.js, 我记得曾经好像安装过vue ,不过现在又要重新开始学习起来了.在youtube上看了一vue的相关教程,还是需要实操的. 好像安装过npm -v 发现已经安装了5.6.0 需要安装然后使用 cnpm 安装 vue-cli 和 webpack 安装代码:npm install -g vue-cli 一.生成项目 首先需要在命令行中进入到项目目录,然后输入: vue init webpack vue-testone p.p1

Vue CLI 3开发中试用UIkit 3组件库

一.UIkit组件库与vuikit简介 在选择好意中的前端开发基本框架后,接下来一个重要任务就是选择一款好的UI组件库.其中,UIkit组件库是一款基于Less+JS的一款轻量级.模块化.响应式的前端UI组件库.特别是,从版本3.0.0 beta 31开始完全脱离了jQuery框架.UIkit组件库的一个重要特点是,其提供的组件大部分是非常基础性的,但是也有一部分组件相当实用,例如Slideshow组件.Upload组件.Video组件等,在github网站上的评价星数是13K,相当不错.另一个

使用@vue/cli初始化项目

Vue CLI 的包名称由 vue-cli 改成了 @vue/cli. 如果你已经全局安装了旧版本的 vue-cli (1.x 或 2.x),你需要先通过 npm uninstall vue-cli -g 卸载它.附上vue-cli官方文档地址 首先检查你的node版本,Vue CLI 需要 Node.js 8.9 或更高版本 (推荐 8.11.0+),命令为 node --version 1.安装vue-cli,-g表示全局安装,这样你才可以直接在命令行使用该指令,否则不行 npm insta

[Vue CLI 3] vue inspect 的源码设计实现

首先,请记住: 它在新版本的脚手架项目里面非常重要 它有什么用呢? inspect internal webpack config 能快速地在控制台看到对应生成的 webpack 配置对象. 首先它是 vue 的一个扩展命令,在文件 @vue/cli/bin/vue.js 中定义了 command 还是依赖了工具包 commander const program = require('commander') 代码配置如下: program .command('inspect [paths...]