vue流程

项目开发流程

脚手架

一、自己搭建(公司搭建属于自己的)  webpack

二、vue-cli  webpack3

三、@vue/cli webpack4

如果你自己的电脑中的是vue-cli,企业用的是@vue/cli

cnpm uninstall vue-cli -g

cnpm install @vue/cli -g

vue create myapp

如果你用的是@vue/cli,但是想用vue-cli创建项目

cnpm install @vue/cli-init -g

vue init webpack myapp

以vue-cli项目为例

1、index.html文件处加入如下代码,以解决移动端点击穿透事件以及不支持promise的情况,如果是PC端项目,跳过此步

<script src="https://as.alipayobjects.com/g/component/fastclick/1.0.6/fastclick.js"></script> <script> if ('addEventListener' in document) { document.addEventListener('DOMContentLoaded', function() { FastClick.attach(document.body); }, false); } if(!window.Promise) { document.writeln('<script src="https://as.alipayobjects.com/g/component/es6-promise/3.2.2/es6-promise.min.js"'+'>'+'<'+'/'+'script>'); } </script>

2、修改目录结构

src

    api

    assets

    components

    lib

    router

    store

    views

    App.vue

    main.js


3、修改相应的文件的配置(首页,分类,购物车,我的,详情)

    3.1 先写好各个页面(页面结构为上下结构,上包含头部和内容,下包含底部)

        src/App.vue

<template>

  <div class="container">

    <div class="box">

      <header class="header">头部</header>

      <div class="content">内容</div>

    </div>

    <footer class="footer">

      <ul>

        <li>

          <span class="iconfont icon-home"></span>

          <p>首页</p>

        </li>

         <li>

          <span class="iconfont icon-fenlei"></span>

          <p>分类</p>

        </li>

         <li>

          <span class="iconfont icon-icon"></span>

          <p>购物车</p>

        </li>

         <li>

          <span class="iconfont icon-wode-copy"></span>

          <p>我的</p>

        </li>

      </ul>

    </footer>

  </div>

</template>

<script>

export default {

}

</script>

<style lang="scss">

@import "~@/lib/reset.scss";

html, body, .container, .detail{

  @include rect(100%, 100%); // width: 100%;height:100%;

}

.container, .detail{

  @include flexbox(); // display:flex;display: box;.... 弹性盒布局的兼容写法

  @include flex-direction(column); // flex-direction: column;

  .box{

    @include flex(); // flex: 1;

    @include rect(100%, auto);

    @include flexbox();

    @include flex-direction(column);

    .header {

      @include rect(100%,0.44rem);

      @include background-color(#f66);

    }

    .content {

      @include flex();

      @include rect(100%, auto);

@include overflow();

    }

  }

  .footer {

    @include rect(100%, 0.5rem);

    @include background-color(#efefef);

    ul {

      @include rect(100%, 100%);

      @include flexbox();

      li {

        @include text-color(#333);

        @include flex();

        @include rect(auto, 100%);

        @include flexbox();

        @include justify-content(); // jusitify-content:center

        @include align-items(); // align-items:center

        @include flex-direction(column);

        span {

          @include font-size(24px);

        }

        p {

          @include font-size(12px);

        }

        &.active {

          @include text-color(#f66);

        }

      }

    }

  }

}

</style>

    3.2 创建各个页面(home/kind/cart/user),以首页为例

    src/views/home/index.vue

<template>

  <div class="box">

    <header class="header">首页头部</header>

    <div class="content">首页内容</div>

  </div>

</template>

<script>

export default {}

</script>

<style lang="scss"></style>

    3.3 抽离App.vue文件中的结构,再创建一个components/Footer.vue

    vue路由的命名视图(多视图路由) ----  一个路由映射多个地方发生改变 ---- 如果没有底部则不传底部

<template>

  <div class="container">

    <router-view></router-view>

    <router-view name="footer"></router-view>

  </div>

</template>

    3.4 配置路由 --- 页面都是通过路由映射出来的 --- components: {default: "",footer: ""}

假设分类页面不需要footer,那么就不传footer 

router/index.js

import Vue from 'vue'

import Router from 'vue-router'

Vue.use(Router)

export default new Router({

  routes: [

    {

      path: "/",

      redirect: '/home'

    },

    {

      path: '/home',

      name: 'home',

      components: { 

        default: () => import('@/views/home'),

        footer: () => import('@/components/Footer')

      }

    },

    {

      path: '/kind',

      name: 'kind',

      components: {

        default: () => import('@/views/kind')

      }

    },

    {

      path: '/cart',

      name: 'cart',

      components: {

        default: () => import('@/views/cart'),

footer: () => import('@/components/Footer')

      }

    },

    {

      path: '/user',

      name: 'user',

      components: {

        default: () => import('@/views/user'),

 footer: () => import('@/components/Footer')

      }

    }

  ]

})

    3.5 配置路由的连接 --- components/Footer.vue

tag属性可以生成目标标签

<template>

  <footer class="footer">

      <ul>

        <router-link to="/home" tag="li">

          <span class="iconfont icon-home"></span>

          <p>首页</p>

        </router-link>

        <router-link to="/kind" tag="li">

          <span class="iconfont icon-fenlei"></span>

          <p>分类</p>

        </router-link>

        <router-link to="/cart" tag="li">

          <span class="iconfont icon-icon"></span>

          <p>购物车</p>

        </router-link>

        <router-link to="/user" tag="li">

          <span class="iconfont icon-wode-copy"></span>

          <p>我的</p>

        </router-link>

      </ul>

    </footer>

</template>

<script>

export default {

}

</script>

如何区分被选中的路由,給li添加如下样式

li.router-link-exact-active.router-link-active {

    @include text-color(#f66);

}

4、数据请求以及状态管理器

    4.1 数据请求 --- 封装接口


cnpm i axios -S

    api/index.js

import axios from 'axios'

import { resolve } from 'dns';

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

// cnpm run dev ----  isDev = true

// cnpm run build ---  idDev = false

// 一般在开发环境下会有跨域问题,生产环境代码在一台服务器下,不存在

// 如果开发遇到跨域问题,需要使用反向代理

// 如果能够解决开发环境与生产环境数据请求的地址呢?

// /daxun 开发环境反向代理标识

// https://www.daxunxun.com 生产环境真实的服务器

const baseUrl = isDev ? '/api' : 'https://www.daxunxun.com'

const api = {

  requestGet (url) {

    return new Promise((resolve, reject) => {

      axios.get(baseUrl + url)

        .then(res => {

          resolve(res.data)

        })

    })

  },

  requestPost (url, data) {

    return new Promise((resolve, reject) => {

      axios.post(baseUrl + url, data)

        .then(res => {

          resolve(res.data)

        })

    })

  }

}

export default api

    如果跨域,需要反向代理

    config/index.js

proxyTable: {

'/daxun': {

        target: 'https://www.daxunxun.com/',

        changeOrigin: true,

        pathRewrite: {

            '^/api': ''

        }

    }

},


 4.2 配置状态管理器

cnpm i vuex -S

store/home.js

export default {

  state: { // 初始化的数据

    homebannerdata: [],

    homeprolist: []

  },

  getters: { // 计算属性

  },

  actions: { // 异步操作

  },

  mutations: { // 唯一改变数据的地方

  }

}

store/index.js,如果有多个页面,需要引入多次

import Vue from 'vue'

import Vuex from 'vuex'

import home from './home'

Vue.use(Vuex)

const store = new Vuex.Store({

  modules: {

 home

  }

})

export default store

    src/main.js将状态管理器添加到vue的根实例

// The Vue build version to load with the `import` command

// (runtime-only or standalone) has been set in webpack.base.conf with an alias.

import Vue from 'vue'

import App from './App'

import router from './router'

import store from './store'

Vue.config.productionTip = false

/* eslint-disable no-new */

new Vue({

  el: '#app',

  router,

 store,

  components: { App },

  template: '<App/>'

})

5、添加UI库的配置

PC: 

element-ui :http://element-cn.eleme.io/2.0/#/zh-CN/component/installation

iview:https://www.iviewui.com/docs/guide/install

移动:

mint-ui:https://mint-ui.github.io/

vant-ui:https://youzan.github.io/vant/#/zh-CN/intro

以mint-ui为例

cnpm i mint-ui -S

cnpm i babel-plugin-component -D

修改.babelrc文件如下:

{

  "presets": [

    ["env", {

      "modules": false,

      "targets": {

        "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]

      }

    }],

    "stage-2"

  ],

"plugins": ["transform-vue-jsx", "transform-runtime",["component", [

    {

      "libraryName": "mint-ui",

      "style": true

    }

  ]]],

  "env": {

    "test": {

      "presets": ["env", "stage-2"],

      "plugins": ["transform-vue-jsx", "transform-es2015-modules-commonjs", "dynamic-import-node"]

    }

  }

}

main.js入口文件处配置mint-ui

// The Vue build version to load with the `import` command

// (runtime-only or standalone) has been set in webpack.base.conf with an alias.

import Vue from 'vue'

import MintUI from 'mint-ui'

import App from './App'

import router from './router'

import store from './store'

Vue.config.productionTip = false

Vue.use(MintUI)

/* eslint-disable no-new */

new Vue({

  el: '#app',

  router,

  store,

  components: { App },

  template: '<App/>'

})

6、搭建页面结构结合UI库

views/home/index.vue

<template>

  <div class="box">

    <header class="header">首页头部</header>

    <div class="content">

 <mt-swipe :auto="4000">

        <mt-swipe-item>1</mt-swipe-item>

        <mt-swipe-item>2</mt-swipe-item>

        <mt-swipe-item>3</mt-swipe-item>

      </mt-swipe>

    </div>

  </div>

</template>

<script>

import Vue from 'vue'

import { Swipe, SwipeItem } from 'mint-ui'

Vue.use(Swipe, SwipeItem)

export default {

}

</script>

<style lang="scss">

.mint-swipe {

  height: 160px;

  border: 1px solid #ccc;

}

</style>

7、数据请求,结合状态管理,并且渲染至页面

    /store/home.js

import api from '@/api'

export default {

  state: { // 初始化的数据

    homebannerdata: [],

    homeprolist: []

  },

  getters: { // 计算属性

  },

  actions: { // 异步操作

gethomebannerdata(context) { // 异步请求数据,context为action中的默认参数,代表是上下文

api.requestGet('/banner') //异步请求数据

        .then(data => {

          console.log(data)

          let arr = []

          data.map((item) => {

            arr.push('https://www.daxunxun.com' + item)

          })

          context.commit('changehomebannerdata', arr) // 显式提交mutation----唯一改变数据源的方式

        })

    },

    gethomeprolist (context) {

      api.requestGet('/douban')

        .then(data => {

          console.log(data)

          context.commit('changehomeprolist', data)

        })

    }

  },

  mutations: { // 唯一改变数据的地方

changehomebannerdata(state, data) {

      state.homebannerdata = data

    },

    changehomeprolist (state, data) {

      state.homeprolist = data

    }

  }

}

    views/home/index.vue

<template>

  <div class="box">

    <header class="header">首页头部</header>

    <div class="content">

      <mt-swipe :auto="4000">

          <img :src="item" alt="" />

        </mt-swipe-item>

      </mt-swipe>

    </div>

  </div>

</template>

<script>

import Vue from 'vue'

import { Swipe, SwipeItem } from 'mint-ui'

import {mapState,mapActions} from 'vuex'

Vue.use(Swipe, SwipeItem)

export default {

  computed: {

 ...mapState({ // 拿到状态管理器中的数据

homebannerdata: (state) => state.home.homebannerdata,

      homeprolist: (state) => state.home.homeprolist

    })

  },

  mounted () {

this.gethomebannerdata()

    this.gethomeprolist()

  },

  methods: {

 ...mapActions([

'gethomebannerdata', // 将 `this.gethomebannerdata()` 映射为 `this.$store.dispatch('gethomebannerdata')`

      'gethomeprolist'

    ])

  }

}

</script>

<style lang="scss">

.mint-swipe {

  height: 160px;

  border: 1px solid #ccc;

}

img {

  width: 100%;

}

</style>

    还可以有等价写法

<template>

  <div class="box">

    <header class="header">首页头部</header>

    <div class="content">

      <mt-swipe :auto="4000">

        <mt-swipe-item v-for = "(item, index) of homebannerdata" :key = "index">

          <img :src="item" alt="" />

        </mt-swipe-item>

      </mt-swipe>

    </div>

  </div>

</template>

<script>

import Vue from 'vue'

import { Swipe, SwipeItem } from 'mint-ui'

import { mapState } from 'vuex'

Vue.use(Swipe, SwipeItem)

export default {

  computed: {

    ...mapState({

      homebannerdata: (state) => state.home.homebannerdata,

      homeprolist: (state) => state.home.homeprolist

    })

  },

  mounted () {

this.$store.dispatch('gethomebannerdata')

    this.$store.dispatch('gethomeprolist')

  }

}

</script>

<style lang="scss">

.mint-swipe {

  height: 160px;

  border: 1px solid #ccc;

}

img {

  width: 100%;

}

</style>

8、列表的渲染以及页面的跳转

编写详情页面 views/detail/index.vue

<template>

  <div class="detail">

    <div class="box">

      <header class="header">

        详情头部

      </header>

      <div class="content">

        详情内容

      </div>

    </div>

    <footer class="footer">

      详情底部

    </footer>

  </div>

</template>

<script>

export default {

}

</script>

views/home/index.vue渲染列表

<template>

  <div class="box">

    <header class="header">首页头部</header>

    <div class="content">

      <mt-swipe :auto="4000">

        <mt-swipe-item v-for = "(item, index) of homebannerdata" :key = "index">

          <img :src="item" alt="" />

        </mt-swipe-item>

      </mt-swipe>

      <ul>

        <li v-for="(item, index) of homeprolist" :key="index" >

          {{ item.title }}

        </li>

      </ul>

    </div>

  </div>

</template>

<script>

import Vue from 'vue'

import { Swipe, SwipeItem } from 'mint-ui'

import { mapState } from 'vuex'

Vue.use(Swipe, SwipeItem)

export default {

  computed: {

    ...mapState({

      homebannerdata: (state) => state.home.homebannerdata,

      homeprolist: (state) => state.home.homeprolist

    })

  },

  mounted () {

    this.$store.dispatch('gethomebannerdata')

    this.$store.dispatch('gethomeprolist')

  }

}

</script>

<style lang="scss">

.mint-swipe {

  height: 160px;

  border: 1px solid #ccc;

}

img {

  width: 100%;

}

</style>

    路由跳转

        修改路由


{

      path: '/detail/:id',

      name: 'detail',

      components: {

        default: () => import('@/views/detail')

      }

    }

        声明式跳转

<template>

  <div class="box">

    <header class="header">首页头部</header>

    <div class="content">

      <mt-swipe :auto="4000">

        <mt-swipe-item v-for = "(item, index) of homebannerdata" :key = "index">

          <img :src="item" alt="" />

        </mt-swipe-item>

      </mt-swipe>

      <ul>

<router-link tag="li" :to = "{name: 'detail', params: {id: item.id}}" v-for="(item, index) of homeprolist" :key="index">

          {{ item.title }}

        </router-link> 

      </ul>

    </div>

  </div>

</template>

<script>

import Vue from 'vue'

import { Swipe, SwipeItem } from 'mint-ui'

import { mapState } from 'vuex'

Vue.use(Swipe, SwipeItem)

export default {

  computed: {

    ...mapState({

      homebannerdata: (state) => state.home.homebannerdata,

      homeprolist: (state) => state.home.homeprolist

    })

  },

  mounted () {

    this.$store.dispatch('gethomebannerdata')

    this.$store.dispatch('gethomeprolist')

  }

}

</script>

<style lang="scss">

.mint-swipe {

  height: 160px;

  border: 1px solid #ccc;

}

img {

  width: 100%;

}

</style>

编程式跳转

<template>

  <div class="box">

    <header class="header">首页头部</header>

    <div class="content">

      <mt-swipe :auto="4000">

        <mt-swipe-item v-for = "(item, index) of homebannerdata" :key = "index">

          <img :src="item" alt="" />

        </mt-swipe-item>

      </mt-swipe>

      <ul>

  •           {{ item.title }}

            </li>

          </ul>

        </div>

      </div>

    </template>

    <script>

    import Vue from 'vue'

    import { Swipe, SwipeItem } from 'mint-ui'

    import { mapState } from 'vuex'

    Vue.use(Swipe, SwipeItem)

    export default {

      computed: {

        ...mapState({

          homebannerdata: (state) => state.home.homebannerdata,

          homeprolist: (state) => state.home.homeprolist

        })

      },

      mounted () {

        this.$store.dispatch('gethomebannerdata')

        this.$store.dispatch('gethomeprolist')

      },

    methods: {

        goDetail (item) {

          // this.$router.push('/detail/' + item.id)

          this.$router.push({

            name: 'detail',

            params: {

              id: item.id

            }

          })

        }

      }

    }

    </script>

    <style lang="scss">

    .mint-swipe {

      height: 160px;

      border: 1px solid #ccc;

    }

    img {

      width: 100%;

    }

    </style>

        详情接收数据

    <template>

      <div class="detail">

        <div class="box">

          <header class="header">

            详情头部

          </header>

          <div class="content">

            详情内容 {{ title }}

          </div>

        </div>

        <footer class="footer">

          详情底部

        </footer>

      </div>

    </template>

    <script>

    import api from '@/api'

    export default {

      data () {

        return {

          title: ''

        }

      },

      mounted () {

        // console.log(this.$route.params.id)

    const id =this.$route.params.id

        api.requestGet('/detail?id=' + id)

          .then(data => {

            console.log(data)

            this.title = data[0].title

          })

      }

    }

    </script>

    9、实现下拉刷新与上拉加载

        views/kind/index.vue

    <template>

      <div class="box">

        <header class="header">分类头部</header>

        <div class="content">

     <mt-loadmore :top-method="loadTop" :bottom-method="loadBottom" :bottom-all-loaded="allLoaded" ref="loadmore">

            <mt-cell v-for="(item, index) of kindlist" :key="index" :title="item.title" label="电影描述" is-link>{{ index }}</mt-cell>

    </mt-loadmore>

        </div>

      </div>

    </template>

    <script>

    import Vue from 'vue'

    import { Cell, Loadmore } from 'mint-ui'

    import api from '@/api'

    Vue.use(Cell, Loadmore)

    export default {

      data () {

        return {

          kindlist: [],

    allLoaded: false,

          pageCode: 1

        }

      },

      mounted () {

        api.requestGet('/douban')

          .then(data => {

            this.kindlist = data

          })

      },

      methods: {

    loadTop () {// 下拉刷新函数

          api.requestGet('/douban')

            .then(data => {

    this.kindlist = data// 重置数据

    this.pageCode = 1 // 页面初始化

    this.allLoaded = false// 表示可以加载数据

    this.$refs.loadmore.onTopLoaded()// 下拉刷新结束

            })

        },

        loadBottom () {

          api.requestGet('/douban?count=20&start=' + this.pageCode * 20)

            .then(data => {

              if (data.length === 0) {

    this.allLoaded = true// 没有数据了

              } else {

    this.kindlist = [...this.kindlist, ...data]// 合并数据

    this.pageCode += 1// 页面加1

              }

    this.$refs.loadmore.onBottomLoaded()// 上拉加载结束

            })

        }

      }

    }

    </script>

    <style lang="scss">

    </style>

  • ©著作权归作者所有,转载或内容合作请联系作者
    • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
      沈念sama阅读 214,029评论 6 493
    • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
      沈念sama阅读 91,238评论 3 388
    • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
      开封第一讲书人阅读 159,576评论 0 349
    • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
      开封第一讲书人阅读 57,214评论 1 287
    • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
      茶点故事阅读 66,324评论 6 386
    • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
      开封第一讲书人阅读 50,392评论 1 292
    • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
      沈念sama阅读 39,416评论 3 412
    • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
      开封第一讲书人阅读 38,196评论 0 269
    • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
      沈念sama阅读 44,631评论 1 306
    • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
      茶点故事阅读 36,919评论 2 328
    • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
      茶点故事阅读 39,090评论 1 342
    • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
      沈念sama阅读 34,767评论 4 337
    • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
      茶点故事阅读 40,410评论 3 322
    • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
      开封第一讲书人阅读 31,090评论 0 21
    • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
      开封第一讲书人阅读 32,328评论 1 267
    • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
      沈念sama阅读 46,952评论 2 365
    • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
      茶点故事阅读 43,979评论 2 351

    推荐阅读更多精彩内容