vue中引入mintui、vux重构简单的APP项目

  最近在学习vue时也了解到一些常用的UI组件,有用于PC的和用于移动端的。用于PC的有:Element(饿了么)、iView等;用于移动端APP的有Vux、Mint UI(饿了么)、Vant(有赞团队)、cube-ui(滴滴)。

  想做一个移动端微信公众号使用的界面,于是选择用mintUI。

   mintUI官网:http://mint-ui.github.io/docs/#/en2/quickstart

1.项目中引入mint-ui

1.下载以及配置

(1)下载:

E:HBuilderSpacevue-demo>cnpm install --save mint-ui

(2)引入:可以按需引入,也可以全部引入

全部引入的方式:

main.js:

import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';
import MintUI from 'mint-ui'
import 'mint-ui/lib/style.css'

Vue.config.productionTip = false;
Vue.use(MintUI)

new Vue({
  router,
  store,
  render: h => h(App),
}).$mount('#app');

比如我们在home.vue使用头部固定的header:(只是简单的实验,需要的时候到官网查阅即可)

<template>
  <div class="home">
    <mt-header title="multiple button">
      <router-link to="/" slot="left">
        <mt-button icon="back">back</mt-button>
        <mt-button @click="handleClose">close</mt-button>
      </router-link>
      <mt-button icon="more" slot="right"></mt-button>
    </mt-header>
    <ul class="footer">
      <router-link class="icons" to="/home/user">个人中心</router-link>
      <router-link class="icons" to="/home/contact">通讯录</router-link>
    </ul>
    <router-view/>
  </div>
</template>

<script>
export default {
  name: 'home',
};
</script>

<style scoped lang="scss">
li{
list-style: none;
}
.footer{
  position: fixed;
  width: 100%;
  height: 60px;
  line-height:60px;
  left: 0px;
  bottom: 0px;
  display: flex;
  flex-flow: row nowrap;
  justify-content: space-around;
}
.icons{
  font-size: 16px;
  flex: 1;
  text-align:center;
  border-top: 1px solid #42b983;
}

a {
  color: #42b983;
    &.active{
     color: #fff;
     background:#42b983;
   }
}
</style>

最终效果如下:

按需引入的方式:(比如我们按需引入所需的按钮模块)

(1)main.js引入模块和css:

import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';
import { Button } from 'mint-ui';
import 'mint-ui/lib/style.css'

Vue.component(Button.name, Button);

Vue.config.productionTip = false;

new Vue({
  router,
  store,
  render: h => h(App),
}).$mount('#app');

 (2).vue文件直接使用:

<mt-button size="large" type="primary">large</mt-button>

结果:

 2. 重构之前的项目,改为mintUI

主要代码如下:

App.vue:只定义了入口,在router/index.js中设置默认路由

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

<style lang="scss">
*{
  padding: 0px;
  text-align: center;
}
</style>

Main.js:按需引入所需的mint模块,并且用Vue.component(name, options)发布为全局组件

import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';
import 'mint-ui/lib/style.css'
import { Button } from 'mint-ui';
import { Field } from 'mint-ui';
import { Header } from 'mint-ui';
import { Navbar, TabItem } from 'mint-ui';

Vue.component(Navbar.name, Navbar);
Vue.component(TabItem.name, TabItem);
Vue.component(Header.name, Header);
Vue.component(Field.name, Field);
Vue.component(Button.name, Button);

Vue.config.productionTip = false;

new Vue({
    router,
    store,
    render: h => h(App),
}).$mount('#app');

router/index.js:

import Vue from 'vue';
import VueRouter from 'vue-router';
import Login from '../views/Login.vue';

Vue.use(VueRouter);

const routes = [
  {
    path: '/',
    name: 'login',
    component: Login,
  },
  {
    path: '/home',
    name: 'home',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/Home.vue'),
    redirect: '/home/user',
    children: [{
      path: 'user',
      name: 'user',
      component: () => import(/* webpackChunkName: "about" */ '../views/User.vue')
    }, {
      path: 'contact',
      name: 'contact',
      component: () => import(/* webpackChunkName: "about" */ '../views/Contact.vue')
    }]
  },
];

const router = new VueRouter({
  mode: 'hash',
  base: process.env.BASE_URL,
  linkActiveClass: 'active',
  routes,
});

export default router;

定义了默认路由是Login,Login采用一次性加载,其他采用懒加载。登录成功之后的/home重定向到子路由/home/user。

store/index.js

import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    username: ''
  },
  mutations: {
    setLoginUsername(state, username) {
      state.username = username
    },
  },
  actions: {
    setLoginUsernameFun(context, username) {
      context.commit("setLoginUsername", username);
    },
  },
  modules: {
  },
});

  vuex管理组件定义了一个属性与修改属性的方法

views/Login.vue

<template>
  <div class="login">
    <form v-if="!isReg">
      <h1>欢迎来到XXX系统</h1>
      <br/>
      <mt-field label="用户名" placeholder="Input username" v-model="name"></mt-field>
      <mt-field label="密    码" placeholder="Input password" type="password" v-model="password"></mt-field>
         <mt-button size="large" type="primary" @click.prevent="login()" key="login">登录</mt-button>
              <br/>
         <mt-button size="large" type="default" @click.prevent="reg()" key="reg" plain>注册</mt-button>
      <br/>
   
    </form>
    <div v-else>
      <h1>注册</h1>
      <br/>
      <br/>
      <mt-field label="用户名" placeholder="Input username" v-model="name"></mt-field>
      <mt-field label="密    码" placeholder="Input password" type="password" v-model="password"></mt-field>
      <mt-field label="密    码" placeholder="Input passwordRepeat" type="password" v-model="passwordRepeat"></mt-field>
         <mt-button size="large" type="primary" @click="addUser()" key="doReg">注册</mt-button>
              <br/>
         <mt-button size="large" type="default" @click="cancel()" key="cancel" plain>取消</mt-button>
    </div>

  </div>
</template>

<script>
import store from '@/store';
import { MessageBox } from 'mint-ui';
import { Toast } from 'mint-ui';

export default {
  name: 'login',
  store,
  data() {
    return {
      isReg: false,
      name: '',
      password: '',
    };
  },
  methods: {
    login() {
      this.isReg = false;
      var nameLocal = localStorage.getItem("name");
      var passwordLocal = localStorage.getItem("password");
      if (nameLocal == '' || passwordLocal == '') {
          MessageBox.alert("您还没注册!", "title");
        return;
      }

      if (nameLocal === this.name && passwordLocal === this.password) {
        store.dispatch("setLoginUsernameFun", nameLocal);
        Toast("登录成功");
        this.$router.push('/home')
        return false;
      }
      
      MessageBox.alert("账号密码错误");
    },
    reg() {
      this.name = '';
      this.password = '';
      this.passwordRepeat = '';
      this.isReg = true;
    },
    addUser() {
       if (this.name == '' || this.password == '') {
                  MessageBox.alert("必填用户名密码!!!");
         return;
       }

      if (this.password !== this.passwordRepeat) {
        MessageBox.alert("两次密码不一致!!!");
        return;
      }

      localStorage.setItem("name", this.name);
      localStorage.setItem("password", this.password);
      this.name = '';
      this.password = '';
      this.isReg = false;
      Toast("注册成功");
    },
    cancel() {
      this.isReg = false;
    }
  },
};
</script>

  定义了两个表单,登录和注册用的,用isReg属性进行切换。注册成功保存到本地localStorage。

  注意:(1)mint中button默认类型是submit,所以需要阻止事件的默认行为。(2)mintUI的JS组件不可以在main.js中全局引入。比如MessageBox、Toast。

views/Home.vue

<template>
    <div class="home">
        <mt-header title="XXX管理系统">
            <router-link to="/" slot="left">
                <mt-button icon="back">back</mt-button>
            </router-link>
            <mt-button icon="more" slot="right"></mt-button>
        </mt-header>

        <router-view/>
        <ul class="footer">
            <router-link class="icons" to="/home/user">个人中心</router-link>
            <router-link class="icons" to="/home/contact">通讯录</router-link>
        </ul>
    </div>
</template>

<script>
    export default {
        name: 'home',
    };
</script>

<style scoped lang="scss">
    li {
        list-style: none;
    }
    
    .footer {
        position: fixed;
         100%;
        height: 60px;
        line-height: 60px;
        left: 0px;
        bottom: 0px;
        display: flex;
        flex-flow: row nowrap;
        justify-content: space-around;
    }
    
    .icons {
        font-size: 16px;
        flex: 1;
        text-align: center;
        border-top: 1px solid #42b983;
    }
    
    a {
        color: #42b983;
        &.active {
            color: #fff;
            background: #42b983;
        }
    }
</style>

  定义了两个子路由,并用secc语法定义了样式。例如样式 a 里面的&.active 会被解析为 a.active,&代表当前选择器。 scoped  代表默认的css作用域是当前页面,如果不写会影响全局css样式,一般为当前页面。

views/Uer.vue

<template>
  <div class="user">
    个人中心。欢迎您: {{getLoginUsername()}}
  </div>
</template>

<script>
import store from '@/store';

export default {
  name: 'User',
  store,
  methods: {
    getLoginUsername() {
      return store.state.username
    },
  },
};
</script>

views/Contact.vue:

<template>
  <div class="user">
    通讯录
  </div>
</template>

3.最终效果:

(1)登录:

 (2)登录之后主页面:

 4.引入axios实现前后端分离的注册、登录效果

1.安装axios

cnpm install --save axios

 2.目录结构

 

3.重要代码解释

src/axios/index.js内容如下:

import axios from "axios";
import { MessageBox } from 'mint-ui';

// 引入常量模块
import Constants from '@/Constants.vue';

// 修改axios请求的默认配置(配置会以一个优先顺序进行合并。这个顺序是:在 lib/defaults.js 找到的库的默认值,然后是实例的 defaults 属性,最后是请求的 config 参数。)
//` baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。
axios.defaults.baseURL = Constants.projectBaseAddress;

// 添加请求拦截器
axios.interceptors.request.use(function(config) {
    // 模拟处理前增加token
    return config;
}, function(error) {
    // 对请求错误做些什么
    return Promise.reject(error);
});

// 添加响应拦截器
axios.interceptors.response.use(function(response) {
    // 对响应数据做点什么
    if(response.data.success) {
        // 如果是成功返回信息之后提取出来返回以供后面的调用链使用(后台返回的JSON数据)
        return response.data;
    } else {
        MessageBox.alert(response.data.msg);
        return new Promise(function(resolve, reject) {
            //                    resolve('success1');
            //                  reject('error');
        });
    }
}, function(error) {
    // 对响应错误做点什么
    return Promise.reject(error);
});

export default axios;

  对axios进行改造之后重新发布对象。所有的请求前面增加一个baseURL,其值是Constants模块的projectBaseAddress。增加拦截器同一对后台返回false的结果进行弹窗,返回为true的提取返回的数据。

src/Constants.vue:

<script>
    export default {
        name: 'Constants',
        projectBaseAddress: '/api'
    };
</script>

  作为一个全局JS工具类发布,使用的方式参考上面axios/index.js中使用。

vue.config.js中使用代理对所有/api/访问进行代理,解决跨域问题。当然跨域也可以后台设置允许跨域。这个参考express跨域设置规则就可以。

module.exports = {
    publicPath: './',
    lintOnSave: false,
    devServer: {
        proxy: {
            '/api': {
                target: 'http://localhost:8088',
                ws: true,
                changeOrigin: true,
                pathRewrite: {
                    '^/api': ''
                }
            }
        }
    }
}

Login.vue进行修改:登录注册采用同步的方式进行登录注册。async关键字+await。登录成功将username、fullname传回前台存入localStorage。

<template>
    <div class="login">
        <form v-if="!isReg">
            <h1>欢迎来到XXX系统</h1>
            <br/>
            <mt-field label="用户名" placeholder="Input username" v-model="username"></mt-field>
            <mt-field label="密    码" placeholder="Input password" type="password" v-model="password"></mt-field>
            <mt-button size="large" type="primary" @click.prevent="login()" key="login">登录</mt-button>
            <br/>
            <mt-button size="large" type="default" @click.prevent="reg()" key="reg" plain>注册</mt-button>
            <br/>

        </form>
        <div v-else>
            <h1>注册</h1>
            <mt-field label="用户名" placeholder="Input username" v-model="username"></mt-field>
            <mt-field label="用户姓名" placeholder="Input userfullname" v-model="userfullname"></mt-field>
            <mt-field label="密    码" placeholder="Input password" type="password" v-model="password"></mt-field>
            <mt-field label="电    话" placeholder="Input phone" v-model="phone"></mt-field>
            <mt-radio title="性    别" v-model="sex" :options="sexOptions" align="right">
            </mt-radio>
            <mt-button size="large" type="primary" @click="addUser()" key="doReg">注册</mt-button>
            <br/>
            <mt-button size="large" type="default" @click="cancel()" key="cancel" plain>取消</mt-button>
        </div>

    </div>
</template>

<script>
    import store from '@/store';
    import { MessageBox } from 'mint-ui';
    import { Toast } from 'mint-ui';
    import axios from "@/axios";

    var login = {
        name: 'login',
        store,
        data() {
            return {
                isReg: false,
                username: '',
                userfullname: '',
                password: '',
                phone: '',
                sex: '',
                sexOptions: [{
                        label: '男性',
                        value: '男'
                    },
                    {
                        label: '女性',
                        value: '女'
                    }
                ]
            };
        },
        methods: {
            async login() {
                this.isReg = false;
                if(this.username == "" || this.password == "") {
                    MessageBox.alert("账号密码必须输入");
                    return;
                }

                var response = await axios.post('/doLoginJSON.html', {
                    username: this.username,
                    password: this.password
                });

                if(response.success) {
                    Toast("登录成功");

                    // 将用户存入localStorage
                    localStorage.setItem("username", response.data.username);
                    localStorage.setItem("userfullname", response.data.userfullname);

                    // 跳转路由
                    this.$router.replace("/home");
                }
            },
            reg() {
                this.username = '';
                this.password = '';
                this.isReg = true;
            },
            async addUser() {
                if(this.username == '' || this.password == '' || this.userfullname == '' || this.phone == '' || this.sex == '') {
                    MessageBox.alert("请检查必填字段!!!");
                    return;
                }

                var response = await axios.post('/user/addUserJSON.html', {
                    username: this.username,
                    userfullname: this.userfullname,
                    password: this.password,
                    phone: this.phone,
                    sex: this.sex,
                });

                if(response.success) {
                    this.isReg = false;

                    Toast("注册成功");
                }
            },
            cancel() {
                this.isReg = false;
            }
        }
    }
    export default login;
</script>

User.vue进行修改:(从localStorage获取当前登录的用户信息)

<template>
    <div class="user">
        个人中心。欢迎您: {{getLoginUsername()}}
    </div>
</template>

<script>
    import store from '@/store';

    export default {
        name: 'User',
        store,
        methods: {
            getLoginUsername() {
                var username = localStorage.getItem("username");
                var userfullname = localStorage.getItem("userfullname");
                return userfullname;
            },
        },
    };
</script>

5.引入Vux

vux官网:https://vux.li/

  查看了vux官网发现git上star的人数也不少,组件也满足自己的使用需求,于是选择了vux。而且vux提供了树形插件、图表统计插件以及常用的md5等工具函数。

1.简介

VUX(读音 [v’ju:z],同 views)是基于WeUI和Vue(2.x)开发的移动端UI组件库,主要服务于微信页面。

基于webpack + vue-loader + vux可以快速开发移动端页面,配合vux-loader方便你在WeUI的基础上定制需要的样式。

vux-loader保证了组件按需使用,因此不用担心最终打包了整个vux的组件库代码。

VUX并不完全依赖于WeUI,VUX 在 WeUI 的基础上扩展了多个常用组件,但是尽量保持整体UI样式接近WeUI的设计规范。

几个名词解释:

vue-loader:用于编译 .vue 文件,官方模板已经帮你配置好。

vux-loader:VUX 组件库的 webpack loader,实现按需加载等功能。它不是替代 vue-loader 而是配合 vue-loader 使用。如果你使用 vux2 模板,暂不需要手动使用它。

官网的建议

  VUX 必须配合 vux-loader 使用,如果不使用 vux2 模板请按照文档正确配置。less@3.x 有严重的兼容问题,请暂时使用 less@^2.7.3。暂未适配 vue-cli@3.x。

 2.安装

(1)安装vux

npm install vux --save

(2)安装less、less-loader (//安装less,vux使用的是less)

npm install less less-loader --save-dev

(3)安装vux-loader:vux是基于vux-loader的,所以必须要安装这个,否则会报一大堆错

npm install vux-loader --save-dev

(4)安装vue-loader:我没安装的时候报错,所以安装了该模块

npm install vue-loader@14.2.2 -D

(5)修改配置:vue.config.js:增加如下配置(vue-cli3.x版本的配置方式)

    configureWebpack: config => {
        require('vux-loader').merge(config, {
            options: {},
            plugins: ['vux-ui']
        })
    }

3.组件的使用:这里使用x-button组件

(1)安装组件,也可以称为注册组件:

局部注册:在模块中引入:

import { XButton } from 'vux'

export default {
  components: {
    XButton
  }
}

全局注册:在main.js中(有点类似于mintui的按需注册组件)

import { XButton } from 'vux'
Vue.component('x-button', XButton)

(2)使用组件:

<x-button type="warn">vux按钮</x-button>

  

至此简单的引入了vux,接下来在使用的时候参考文档使用所需组件即可。

补充:关于vux的不一样的地方

(1)@click 绑定事件不生效。按照Vue文档,在组件上绑定原生点击事件请使用@click.native。

6.错误小记载

(1)npm run build的时候报错:

Invalid options object. CSS Loader has been initialised using an options object that does not match the API schema.
- options has an unknown property 'minimize'

在css-loader1.0版本的时候移除了该属性,我没有找到替代办法,所以我选择了降低css-loader版本解决:

npm install css-loader@0.28.11

总结:

0.@代表的是src目录

1.vue中引入全局JS变量和JS方法有两种:

(1)将全局的东西提取到单独的模块中,比如:抽到Constants.vue中,内容如下

<script>
    export default {
        name: 'Constants',
        projectBaseAddress: '/api',
        method1() {
            return "method1";
        }
    };
</script>

其他模块使用的方法:引入模块,使用即可:

import Constants from '@/Constants.vue';
console.log(Constants.projectBaseAddress);
console.log(Constants.method1());

(2)通过Vue.prototype挂载到Vue实例中。可以挂载对象、函数、变量等,也可以是从模块中引入的对象。

var Constants = {
    name: 'Constants',
    projectBaseAddress: '/api',
    method1() {
        return "method1";
    }
};
Vue.prototype.Constants = Constants;

组件中调用即可:

console.log(this.Constants);

2.axios是基于Promise的ajax库,可以用async+await实现同步请求,其拦截器也可以做一些统一处理。

3.axios跨域请求可以在后台设置允许跨域+携带cookie,之后设置axios携带cookie。也可以使用代理,上面是使用了代理。

前台git地址:https://github.com/qiao-zhi/vue-demo.git

 后台git地址:https://github.com/qiao-zhi/springboot-ssm

原文地址:https://www.cnblogs.com/qlqwjy/p/11954661.html