Vue教程--Wap端项目搭建从0到1(详解1)

本文基于工作项目开发,做的整理笔记
前段时间公司有的小伙伴刚开始学习vue,就直接着手用在新项目上,以项目实战步步为营,不断推进vue的学习和使用。时间短,需求多,又是刚刚上手,遇到的坑和困难也真不少,感觉每天都在疯狂地解决问题。说真的,每种技术的学习和使用,在实际项目的开发上得到了充分检验,个人能力也在快速的成长。
前一段时间,写过文章“Vue教程--使用官方脚手架构建实例”,主要是针对PC端,架构而写。当初的目的,也是想做为一个入门的教程,但是根据反馈和自己后面的感受,发现并不是很好,并没有做到真正的一步步上手。
今天决定专门针对Wap端去做这样一个demo,整体架构的搭建,并含有一些通用的功能。其中,部分知识点请回看前面那篇文章。对比来看,此篇应该更为详细,步步为营。

前提条件:
你已经了解vue的基础知识,尝试过使用vue-cli官方脚手架搭建项目。

编码环境:
system:OS X EI Capitan 10.12.5
npm:5.4.2
node:v8.8.0
vue-cli:@lastest

相关技术栈:
vue2 + vuex + vue-router + webpack + ES6/7 + fetch/axios + sass + flex + svg

相关地址:
项目代码github地址:https://github.com/YuxinChou/vue-wap-demo
项目在线地址:http://www.knowing365.com
(可用手机扫描下文中二维码,或用chrome浏览器模拟手机访问)
参考项目:https://github.com/bailicangdu/vue2-elm

Vue教程--Wap端项目搭建从0到1(详解1)_第1张图片
WAP端项目搭建从0到1.jpg

目录
| - 0.传送门
| - 1.安装
| - 2.项目说明
| - 3.项目搭建
  | - Step1. 初始化
  | - Step2. 母版页Layout
  | - Step3. 配置rem
  | - Step4. 配置sass
  | - Step5. 顶部导航header
  | - Step6. 引入iconfont
  | - Step7. 侧边菜单sidebar
  | - Step8. 底部导航footer
  | - Step9. 返回顶部backToTop(组件)
  | - Step10. 仓库存储store
  | - Step11. 侧边菜单状态保存
  | - Step12. 搜索栏searchBar(组件)
  | - Step13. 页面添加
  | - Step14. 弹窗提示(组件)
  | - ---------------------------------- 下内容为详解2
  | - Step15. 完善login页面(fetch请求数据)
  | - Step16. 合理引入svg
  | - Step17. 用axios实现请求(取代原生fetch)
  | - Step18. 登录状态存入仓库
  | - Step19. 滚动加载更多(组件)
  | - Step20. 回到指定位置(组件)
  | - Step21. 完善消息列表页面
  | - Step22. 顶部菜单改造(slot的使用)
  | - --------------------------------- 下内容为详解3
  | - Step23. 完善其他页面
  | - Step24. 权限检查
  | - Step25. 页面切换动画transition
  | - Step26. 轮播展示(swiper)
  | - Step26. 分享功能(vue-social-share)
  | - Step28. ...
| - 4.项目部署
  | - a)本地部署
  | - b)服务器部署
| - 5.后续

0.传送门

官网“起步”传送门:http://cn.vuejs.org/v2/guide/#起步

1.安装

你已经安装了npm,它是随node.js安装的,装了node.js也就有了它。
node.js安装下载地址:http://nodejs.cn/download/

# 检查node.js是否安装,若有则显示版本号
$ node -v
# 检查npm的版本号
$ npm -v
# 若要更新npm,使用
$ npm install npm@latest -g

一般,我们还会安装淘宝镜像cnpm,因为在墙内,有时候使用npm安装会很慢,所以需要。

# 安装cnpm,并指定镜像地址
$ npm install -g cnpm --registry=https://registry.npm.taobao.org

写文章时,我的目前版本如下:

Yuxin's MacBook Pro:Vue yuxin$ node -v
v8.8.0
Yuxin's MacBook Pro:Vue yuxin$ npm -v
5.4.2
Yuxin's MacBook Pro:Vue yuxin$ cnpm -v
[email protected] (/usr/local/lib/node_modules/cnpm/parse_argv.js)
[email protected] (/usr/local/lib/node_modules/cnpm/node_modules/npm/lib/npm.js)
[email protected] (/usr/local/bin/node)
[email protected] (/usr/local/lib/node_modules/cnpm/node_modules/npminstall/lib/index.js)
prefix=/usr/local 
darwin x64 16.6.0 
registry=https://registry.npm.taobao.org

vue的安装:

# 最新稳定版
$ npm install vue
# 它的命令行工具
$ npm install --global vue-cli   

我们接下来就使用它的命令行工具 vue-cli 来构建项目
(类似的还有在react.js方面,快速上手会使用到‘蚂蚁金服’的Ant-design,使用antd-init或者dva-cli,都是命令行构建项目。)

2.项目说明

以【QQ手机APP】为UI界面参考,从母版页,列表页,左侧菜单,上下菜单,顶部导航,滚动加载,权限等页面及功能一一按步骤开发完成。那么这里的思路是:

  • 先搭建母版页Layout
  • 顶部导航header
  • 侧边菜单sidebar
  • 上下菜单navbar(扩展)
  • 底部导航footer
  • 页面添加
  • 功能(返回顶部,滚动加载...)
  • 接口请求
  • 仓库存储
  • 权限检查
  • ...

整体的页面效果,大概如下:

vue-wap-demo.jpg

二维码访问,或者访问线上地址
(注:未作PC兼容,请使用chrome手机模式访问)


项目demo代码:GitHub地址


3.项目搭建

使用命令行工具,开始一点点构建项目:

Step1. 初始化

去到你的指定目录,初始化项目,名称为vue-wap-demo
(注意:ESLint那里我选择了None模式,为了简单)

# 去到放项目的文件夹地址
Yuxin's MacBook Pro:Vue yuxin$ cd /Users/yuxin/Documents/Season/Project/Vue 
# 创建基于webpack模版的项目,名称为vue-wap-demo
Yuxin's MacBook Pro:Vue yuxin$ vue init webpack vue-wap-demo

? Project name vue-wap-demo  //直接回车(不修改的话)
? Project description A Vue.js project  //直接回车
? Author Season   //直接回车
? Vue build standalone //直接回车
? Install vue-router? Yes  //我选择了Yes
? Use ESLint to lint your code? Yes  //我选择了Yes
? Pick an ESLint preset none  //我选择了None模式!!!(注意:这里我用了None,为了简单)
? Setup unit tests with Karma + Mocha? No  //我选择了No(暂时不需要)
? Setup e2e tests with Nightwatch? No  //我选择了No(暂时不需要)

   vue-cli · Generated "vue-wap-demo".

   To get started:
   
     cd vue-wap-demo
     npm install
     npm run dev
   
   Documentation can be found at https://vuejs-templates.github.io/webpack

执行上面提示中的命令,把项目运行起来

# 进入项目文件夹
Yuxin's MacBook Pro:Vue yuxin$ cd vue-wap-demo
# 安装
Yuxin's MacBook Pro:vue-wap-demo yuxin$ npm install

> [email protected] install /Users/yuxin/Documents/Season/Project/Vue/vue-wap-demo/node_modules/fsevents
> node install

[fsevents] Success: "/Users/yuxin/Documents/Season/Project/Vue/vue-wap-demo/node_modules/fsevents/lib/binding/Release/node-v57-darwin-x64/fse.node" already installed
Pass --update-binary to reinstall or --build-from-source to recompile

> [email protected] postinstall /Users/yuxin/Documents/Season/Project/Vue/vue-wap-demo/node_modules/uglifyjs-webpack-plugin
> node lib/post_install.js

npm notice created a lockfile as package-lock.json. You should commit this file.
added 1059 packages in 26.516s

# 运行
Yuxin's MacBook Pro:vue-wap-demo yuxin$ npm run dev

> [email protected] dev /Users/yuxin/Documents/Season/Project/Vue/vue-wap-demo
> node build/dev-server.js

> Starting dev server...


 DONE  Compiled successfully in 2324ms                                  14:38:51

浏览器查看,效果如下:

Vue教程--Wap端项目搭建从0到1(详解1)_第2张图片
项目初始化效果.jpg

此时,项目代码结构如下:

# 当前代码结构
vue-wap-demo
├── build                      // 构建相关  
├── config                     // 配置相关
├── node_modules               // 模块安装的文件夹
├── src                        // 核心代码
│   ├── assets                 // 静态资源
│   ├── components             // 组件
│   ├── router                 // 路由
│   ├── App.vue                // 入口页面
│   └── main.js                // 入口 加载组件 初始化等
├── static                     // 第三方不打包资源
├── .babelrc                   // babel-loader 配置
├── .editorconfig              // 代码编辑 配置项
├── .eslintignore              // eslint 忽略项
├── .eslintrc.js               // eslint 配置项
├── .gitignore                 // git 忽略项
├── favicon.ico                // favicon图标
├── index.html                 // html模板
├── package-lock.json          // package-lock.json
├── package.json               // package.json
└── �README.md                  // 说明文档

# 注意!!!
# 下面是教程结束时的代码结构(可忽视)
vue-wap-demo
├── build                      // 构建相关  
├── config                     // 配置相关
├── dist                       // 打包的部署文件
├── node_modules               // 模块安装的文件夹
├── screenshots                // 项目截图
├── src                        // 核心代码
│   ├── assets                 // 静态资源
│   ├── components             // 组件
│   ├── page                   // 页面
│   ├── router                 // 路由
│   ├── service                // 请求服务
│   ├── store                  // 仓库存储
│   ├── style                  // 样式
│   ├── utils                  // 公用方法
│   ├── App.vue                // 入口页面
│   └── main.js                // 入口 加载组件 初始化等
├── static                     // 第三方不打包资源
├── .babelrc                   // babel-loader 配置
├── .editorconfig              // 代码编辑 配置项
├── .eslintignore              // eslint 忽略项
├── .eslintrc.js               // eslint 配置项
├── .gitignore                 // git 忽略项
├── favicon.ico                // favicon图标
├── index.html                 // html模板
├── package-lock.json          // package-lock.json
├── package.json               // package.json
└── �README.md                  // 说明文档

Step2. 母版页Layout

初始化后,在是src/components路径下默认有一个HelloWorld.vue页面,我们将其改名为Layout.vue作为母版页,调整一下内容,如下:

/**********************************************/
/* src/components/Layout.vue                  */
/**********************************************/






同时需要修改router/index.js的内容,把HelloWorld的相关引用改为Layout,如下:

/**********************************************/
/* src/router/index.js                        */
/**********************************************/

import Vue from 'vue'
import Router from 'vue-router'
import Layout from '@/components/Layout'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'Layout',
      component: Layout
    }
  ]
})

现在我们可以看见修改后的效果。(开发的时候,一直保持项目运行就可以了)

Step3. 配置rem

src文件夹下创建utils文件夹,并添加文件rem.js,代码如下:

/**********************************************/
/* src/utils/rem.js                           */
/**********************************************/

(function(doc, win) {
    var docEl = doc.documentElement,
        resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
        recalc = function() {
            var clientWidth = docEl.clientWidth;
            if (!clientWidth) return;
            docEl.style.fontSize = 20 * (clientWidth / 320) + 'px';
        };
    if (!doc.addEventListener) return;
    win.addEventListener(resizeEvt, recalc, false);
    doc.addEventListener('DOMContentLoaded', recalc, false);
})(document, window);

// 注解:
// 设计稿为320的时候,1rem=20px
// 设计稿为640的时候,1rem=40px
// 设计稿宽768的时候,1rem=48px

rem.js引入到src\main.js中,即插入代码import './utils/rem',最终代码如下:

/**********************************************/
/* src/main.js                                */
/**********************************************/

// 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 './utils/rem'

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  template: '',
  components: { App }
})

此时,再看运行后的效果,使用chrome手机模式预览,可以发现rem已经生效。

Step4. 配置sass

整个项目过程中我们将使用sass,但是目前还没有配置。我们先修改Layout.vue,将它的style改成sass写法,如下:

/**********************************************/
/* src/components/Layout.vue                  */
/**********************************************/

...


// 注解:
// 仅修改style这里,其他代码不变
// 注意添加lang="scss"

保存修改之后,我们可以看到终端报错。根据终端显示的错误信息和安装提示,我们可以一步步解决这个问题。

# 按提示安装sass-loader
$ npm install sass-loader 横线横线save(双横线自动连起来了)
# 按提示安装node-sass
$ npm install node-sass 横线横线save(双横线自动连起来了)

再启动运行项目,没有报错,sass已经可以正常使用了。那么我们可能会疑问,为什么安装缺失的模块之后就可以用了呢?答案就在build文件夹下的配置中,想研究一下的可以去看看其中的webpack.base.conf.jsutilsl.js两个文件。

Step5. 顶部导航header

src/components中创建header文件夹,并创建head.vue,其代码如下:

/**********************************************/
/* src/components/header/head.vue             */
/**********************************************/







接着,我们在Layout.vue中引用head组件,代码如下:

/**********************************************/
/* src/components/Layout.vue                  */
/**********************************************/






这里需要注意一点,我用的是,而非

,这是因为headerhtml的关键字,类似的命名都不能使用。

其次,为什么在script中的引用是headTop,而在html里的书写就变成了head-top。这个可以去查下,根据大写字母自动转变成-连接。

Layout.vue中,我们还做了一件事,就是把src/App.vue中的logo图片那段代码暂时移动到这里了。同时,我们把src/App.vue中的style样式删除,下面将引入全站样式文件。此时,src/App.vue的代码如下:

/**********************************************/
/* src/App.vue                                */
/**********************************************/




Step6. 引入iconfont

上面我们说引入全站样式,在src下创建style文件夹,并依次添加样式入口文件index.scss,全站样式文件common.scss,字体样式文件iconfont.scss,mixin文件mixin.scss,如下:

/**********************************************/
/* src/style/index.scss                       */
/**********************************************/

@import "./common.scss";
@import "./iconfont.scss";
@import "./mixin.scss";
/**********************************************/
/* src/style/common.scss                      */
/**********************************************/

body,
div,
span,
header,
footer,
nav,
section,
aside,
article,
ul,
dl,
dt,
dd,
li,
a,
p,
h1,
h2,
h3,
h4,
h5,
h6,
// i,
b,
textarea,
button,
input,
select,
figure,
figcaption,
{
    padding: 0;
    margin: 0;
    list-style: none;
    font-style: normal;
    text-decoration: none;
    border: none;
    color: #333;
    font-weight: normal;
    font-family: "Microsoft Yahei";
    box-sizing: border-box;
    -webkit-tap-highlight-color: transparent;
    -webkit-font-smoothing: antialiased;
    &:hover {
        outline: none;
    }
}


/*定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/

::-webkit-scrollbar {
    width: 0px;
    height: 0px;
    background-color: #F5F5F5;
}


/*定义滚动条轨道 内阴影+圆角*/

::-webkit-scrollbar-track {
    -webkit-box-shadow: inset 0 0 1px rgba(0, 0, 0, 0);
    border-radius: 10px;
    background-color: #F5F5F5;
}


/*定义滑块 内阴影+圆角*/

::-webkit-scrollbar-thumb {
    border-radius: 10px;
    -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .3);
    background-color: #555;
}


/*定义自动填充数据背景色*/

input:-webkit-autofill {
    -webkit-box-shadow: 0 0 0px 1000px #fff inset;
    -webkit-text-fill-color: #666;
}


/*定义placeholder提示的颜色*/

::-webkit-input-placeholder {
    /* WebKit browsers */
    // font-size: 0.6rem;
    color: #999;
}

:-moz-placeholder {
    /* Mozilla Firefox 4 to 18 */
    // font-size: 0.6rem;
    color: #999;
}

::-moz-placeholder {
    /* Mozilla Firefox 19+ */
    // font-size: 0.6rem;
    color: #999;
}

:-ms-input-placeholder {
    /* Internet Explorer 10+ */
    // font-size: 0.6rem;
    color: #999;
}

input[type="button"],
input[type="submit"],
input[type="search"],
input[type="reset"] {
    -webkit-appearance: none;
}

textarea {
    -webkit-appearance: none;
}

html,
body {
    height: 100%;
    width: 100%;
    background-color: #f5f5f5; //transparent;
    font-size: 0.6rem;
}

.clear:after {
    content: '';
    display: block;
    clear: both;
}

.clear {
    zoom: 1;
}

.back_img {
    background-repeat: no-repeat;
    background-size: 100% 100%;
}

.margin {
    margin: 0 auto;
}

.left {
    float: left;
}

.right {
    float: right;
}

.hide {
    display: none;
}

.show {
    display: block;
}

.ellipsis {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.paddingTop {
    padding-top: 1.95rem;
}

@keyframes backOpacity {
    0% {
        opacity: 1
    }
    25% {
        opacity: .5
    }
    50% {
        opacity: 1
    }
    75% {
        opacity: .5
    }
    100% {
        opacity: 1
    }
}

.animation_opactiy {
    animation: backOpacity 2s ease-in-out infinite;
}
/**********************************************/
/* src/style/iconfont.scss                    */
/**********************************************/

// 暂时没有内容
/**********************************************/
/* src/style/mixin.scss                       */
/**********************************************/

// 暂时没有内容

既然已经创建了文件,我们就可以将样式用于项目,在src/main.js中引入index.scss,代码如下:

/**********************************************/
/* src/main.js                                */
/**********************************************/

// 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 './config/rem'
import './style/index.scss';       //仅插入这句

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  template: '',
  components: { App }
})

此时,我们的iconfont.scss文件其实已经被引用到项目中了,但是因为没有字体样式的内容,没有效果。

我们使用iconfont-阿里巴巴矢量图标库来为项目创建字体。登陆帐号后,添加字体,创建项目,下载项目字体,我们就可以拿来使用了。下载的字体文件包内容如下:

# 下载的字体文件包内容
font package
├── demo_fontclass.html             // class使用方式(demo)  
├── demo_symbol.html                // symbol使用方式(demo)  
├── demo_unicode.html               // unicode使用方式(demo)  
├── demo.css                        // 样式文件(demo)  
├── iconfont.css                    // 字体样式
├── iconfont.eot                    // 字体文件
├── iconfont.js                     // 字体脚本
├── iconfont.svg                    // 字体文件
├── iconfont.ttf                    // 字体文件
└── iconfont.woff                   // 字体文件

当然,你也可以选择使用字体在线路径进行引用,不过我一般没有这么做。

src/assets中创建iconfont文件夹,将iconfont.eoticonfont.svgiconfont.ttficonfont.woff放入其中,接着修改iconfont.scss文件,内容如下:

/**********************************************/
/* src/style/iconfont.scss                    */
/**********************************************/
@font-face {
    font-family: "iconfont";
    src: url('../assets/iconfont/iconfont.eot?t=1509583688642');
    /* IE9*/
    src: url('../assets/iconfont/iconfont.eot?t=1509583688642#iefix') format('embedded-opentype'), /* IE6-IE8 */
    url('../assets/iconfont/iconfont.woff?t=1509583688642') format('woff'), /* chrome, firefox */
    url('../assets/iconfont/iconfont.ttf?t=1509583688642') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
    url('../assets/iconfont/iconfont.svg?t=1509583688642#iconfont') format('svg');
    /* iOS 4.1- */
}

.iconfont {
    font-family: "iconfont" !important;
    font-size: 0.8rem;
    font-style: normal;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

.icon-category:before {
    content: "\e699";
}

.icon-fanhui:before {
    content: "\e6e3";
}

.icon-tianjia:before {
    content: "\e6a5";
}

.icon-tianjia-circle:before {
    content: "\e68e";
}

.icon-xiaoxi:before {
    content: "\e672";
}

.icon-lianxiren:before {
    content: "\e63d";
}

.icon-dongtai:before {
    content: "\e602";
}

.icon-404:before {
    content: "\e60c";
}

.icon-search:before {
    content: "\e620";
}

.icon-vip:before {
    content: "\e603";
}

.icon-wallet:before {
    content: "\e625";
}

.icon-grab:before {
    content: "\e604";
}

.icon-favor:before {
    content: "\e61f";
}

.icon-photo:before {
    content: "\e63f";
}

.icon-file:before {
    content: "\e621";
}

.icon-setting:before {
    content: "\e8ea";
}

.icon-night:before {
    content: "\e653";
}

.icon-profile:before {
    content: "\e631";
}

.icon-phone:before {
    content: "\e626";
}

.icon-totop:before {
    content: "\e600";
}

.icon-QQ:before {
    content: "\e647";
}

.icon-arrow-down:before {
    content: "\e6a6";
}

.icon-arrow-right:before {
    content: "\e6a7";
}

注意:这里的代码和字体文件,已经包含整个项目所用到的全部字体。

此时,我们看运行后的项目效果,headertoggleButton按钮已经显示字体。我们又发现不对了,这里是字体按钮,可是在线demo和效果截图中,这个按钮是一个头像图片,这个下一步我们再替换下。

Step7. 侧边菜单sidebar

src/components中创建sidebar文件夹,并创建sidebar.vue,其代码如下:

/**********************************************/
/* src/components/sidebar/sidebar.vue         */
/**********************************************/





接着,我们在Layout.vue中引用sidebar组件,代码如下:

/**********************************************/
/* src/components/Layout.vue                  */
/**********************************************/






现在,我们把sidebar组件引入了,但是发现控制样式的类hideSidebar受到顶部导航header的变量sidebar控制,需要将变量放置在Layout.vue中,并且在侧边菜单显示的时候需要一个遮罩层masking

src/components中创建masking文件夹,并创建masking.vue,其代码如下:

/**********************************************/
/* src/components/masking/masking.vue         */
/**********************************************/






修改Layout.vue,引入masking组件,并添加sidebar变量及toggleSideBar方法,稍后header组件调用。

/**********************************************/
/* src/components/Layout.vue                  */
/**********************************************/






修改header.vue文件,代码如下:

/**********************************************/
/* src/components/header/head.vue             */
/**********************************************/





现在来看一下效果,我们要的功能已经实现了。

Step8. 底部导航footer

src/components中创建footer文件夹,并创建footer.vue,其代码如下:

/**********************************************/
/* src/components/footer/footer.vue             */
/**********************************************/






接着,我们在Layout.vue中引用footer组件,代码如下:

/**********************************************/
/* src/components/Layout.vue                  */
/**********************************************/






那么做到这里,我们就已经能够将一个APP的基本结构用组件方式拼装起来,这个母版页将可以用在多个页面。我们已经掌握了这部分技能。

但是,现在我们再回去看一下需要实现的demo,我们发现并不是所有页面都有footer,每个页面的header也不大相同。我们未来需要调整母版页Layout的代码,把顶部导航和底部导航丢到各个具体页面上。

Step9. 返回顶部backToTop(组件)

返回顶部也是一个常用的功能,看一下实现。在src/components中创建common文件夹,并创建backToTop.vue,其代码如下:

/**********************************************/
/* src/components/common/backToTop.vue        */
/**********************************************/





headerfooter一样,在Layout.vue中引用就好了,这里不单独贴代码了。

Step10. 仓库存储store

为了后面能把headerfooter移出Layout,放入每个单独的页面,我们需要把控制侧边菜单状态的变量存放在仓库store中管理。下面看看如何实现。

src中创建store文件夹,并创建以下目录及文件:

store
├── modules                       // 仓库模块
│     ├── app.js                  // 基础模块(存放sidebar状态等)
│     ├── common.js               // 页面模块(存放页面数据,晚点用到)
│     └── user.js                 // 用户模块(存放用户信息,晚点用到)
├── getters.js                    // 计算属性
└── index.js                      // 入口文件

其中,index.jsgetters.jsmodules/app.js的代码如下:

/**********************************************/
/* src/store/index.js                         */
/**********************************************/

import Vue from 'vue';
import Vuex from 'vuex';
import app from './modules/app';
import getters from './getters';

Vue.use(Vuex);

const store = new Vuex.Store({
    modules: {
        app
    },
    getters
});

export default store
/**********************************************/
/* src/store/getter.js                        */
/**********************************************/

const getters = {
    sidebar: state => state.app.sidebar
};

export default getters
/**********************************************/
/* src/store/modules/app.js                   */
/**********************************************/

import Cookies from 'js-cookie';

const app = {
    state: {
        sidebar: !+Cookies.get('sidebarStatus')
    },
    mutations: {
        TOGGLE_SIDEBAR: state => {
            if (state.sidebar) {
                Cookies.set('sidebarStatus', 1);
            } else {
                Cookies.set('sidebarStatus', 0);
            }
            state.sidebar = !state.sidebar;
        },
    },
    actions: {
        ToggleSideBar: ({ commit }) => {
            commit('TOGGLE_SIDEBAR')
        },
    }
};

export default app;

modules/app.js中,我们用了一个模块js-cookie,需要安装一下,如下:

$ npm install js-cookier --save

安装好了即可。

接着我们在main.js中引入store,代码如下:

/**********************************************/
/* src/main.js                                */
/**********************************************/

// 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 './config/rem'
import './style/index.scss';
import store from './store/index'     // 插入这句

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  store,              // 插入这句
  template: '',
  components: { App }
})

此时仓库存储就搭建好了。

Step11. 侧边菜单状态保存

先修改Layout,将sidebar变量改成从仓库中获取;再修改header,调用仓库的方法改变sidebar的值。

/**********************************************/
/* src/components/Layout.vue                  */
/**********************************************/






/**********************************************/
/* src/components/header/head.vue                  */
/**********************************************/






此时,我们查看效果,这一块已经完成。

Step12. 搜索栏searchBar(组件)

查看我们要做的demo页面,发现很多页面有一个公共组件searchBar,我们先把这个处理一下。

src/components/common中添加searchBar.vue,代码如下:

/**********************************************/
/* src/components/common/searchBar.vue        */
/**********************************************/





代码中有一个事件,它的作用就是跳转到搜索页面,那么稍后我们添加这个页面,并添加相关路由。

Step13. 页面添加

现在我们先整理一下Layout.vue,把headerfooter移出去,等下将他们放在各个页面中。这里,我们还把页面的实际内容代码,用替换,这个位置将渲染页面的具体内容。整理后的Layout.vue,代码如下:

/**********************************************/
/* src/components/Layout.vue                  */
/**********************************************/







src中创建page文件夹,并创建以下文件:

page
├── messages
│     └── messages.vue             // 消息页面
├── contacts
│     └── contacts.vue             // 联系人页面
├── dynamics
│     └── dynamics.vue             // 动态页面
├── search
│     └── search.vue               // 搜索页面
├── login
│     └── login.vue                // 登陆页面
├── error
│     └── pageNotFound.vue         // 404页面
├── ...
├── ...
└── 其他请看源码

所有页面的代码先如下:

/**********************************************/
/* 上述新创建页面                               */
/**********************************************/




上面代码,表示每个页面只是带有一句描述的空页面。下面,我们把路由补全,修改src/router/index.js,代码如下:

/**********************************************/
/* src/router/index.js                        */
/**********************************************/

import Vue from 'vue'
import Router from 'vue-router'
import Layout from '@/components/Layout'

const Login = r => require.ensure([], () => r(require('../page/login/login')), 'Login')

const Messages = r => require.ensure([], () => r(require('../page/messages/messages')), 'messages')
const Contacts = r => require.ensure([], () => r(require('../page/contacts/contacts')), 'contacts')
const Dynamics = r => require.ensure([], () => r(require('../page/dynamics/dynamics')), 'dynamics')
const Search = r => require.ensure([], () => r(require('../page/search/search')), 'search')

const PageNotFound = r => require.ensure([], () => r(require('../page/error/pageNotFound')), 'pageNotFound')

Vue.use(Router)

export default new Router({
    mode: "history",
    routes: [
        { path: '/login', name: 'Login', component: Login },
        {
            path: '/',
            component: Layout,
            children: [
                { path: '', redirect: '/login' },
                { path: '/messages', name: 'Messages', component: Messages },
                { path: '/contacts', name: 'Contacts', component: Contacts },
                { path: '/dynamics', name: 'Dynamics', component: Dynamics },
                { path: '/search', name: 'Search', component: Search }
            ]
        },
        { path: '*', component: PageNotFound }

    ]
})

下面,我们通过修改URL,看一下是否可以访问所有页面。

Step14. 弹窗提示(组件)

考虑到要用到“提示”,我们先添加一个这样的组件。在src/components/common中添加alertTip.vue,代码如下:

/**********************************************/
/* src/components/common/alertTip.vue         */
/**********************************************/

 




之后login页面请求的时候,我们再看看是如何使用的。

由于文章篇幅限制,请继续阅读Vue教程--Wap端项目搭建从0到1(详解2)。


学习是一条漫漫长路,每天不求一大步,进步一点点就是好的。

你可能感兴趣的:(Vue教程--Wap端项目搭建从0到1(详解1))