vue-cli安装以及创建一个简单的项目(二)(vuex使用、发行一个简单的app)

时间:2023-03-09 00:34:37
vue-cli安装以及创建一个简单的项目(二)(vuex使用、发行一个简单的app)

1.vuex的使用

  vuex是vue的状态管理中心,vuex来保存我们需要管理的状态值,值一旦被修改,所有引用该值的地方就会自动更新,常用于:

1.多个视图依赖同一状态(l例:菜单导航)

2.来自不同视图的行为需要变更同一状态(例如评论弹幕)

上篇创建的vue项目目录结构:

vue-cli安装以及创建一个简单的项目(二)(vuex使用、发行一个简单的app)

  在上一节我们已经安装了vuex模块。查看store/index.js内容,如下:

import Vue from 'vue';
import Vuex from 'vuex'; Vue.use(Vuex); export default new Vuex.Store({
state: {
},
mutations: {
},
actions: {
},
modules: {
},
});

  上面引入Vue模块和Vuex模块,并将Vuex安装到Vue中。

下面使用vuex。在Test路由中改变值,在about模块中接收,代码如下:

(1)修改store/index.js

import Vue from 'vue';
import Vuex from 'vuex'; Vue.use(Vuex); export default new Vuex.Store({
state: {
count: 0,
},
mutations: {
increase() {
this.state.count = this.state.count + 1;
},
},
actions: {
},
modules: {
},
});

  定义一个状态count,mutations中是修改状态的唯一入口。

(2)修改Test.vue

<template>
<div class="test">
这是Test
<button tybe="button" @click="addOne()">点击我</button>
</div>
</template> <script>
import store from '@/store'; export default {
name: 'Test',
store,
methods: {
addOne() {
console.log('add');
store.commit('increase');
},
},
};
</script>

  点击按钮的时候调用方法addOne()。addOne()中调用store.commit("increase") 提交该方法进行修改状态,相当于调用 Vuex.Store 实例的 increase() 方法。

(3)修改About.vue接收状态count

<template>
<div class="about">
<h1>This is an about page</h1>
{{msg}}
</div>
</template> <script>
import store from '@/store'; export default {
name: 'About',
store,
data() {
return {
msg: store.state.count,
};
},
};
</script>

(4)测试:

vue-cli安装以及创建一个简单的项目(二)(vuex使用、发行一个简单的app)

补充:关于vuex调用函数传递参数。比如我们传递一个username参数到vuex中,如:

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: {
},
});

调用方法如下:(登录成功之后跳转到首页并记录登录的用户)=如下面红色代码

    login() {
this.isReg = false;
var nameLocal = localStorage.getItem("name");
var passwordLocal = localStorage.getItem("name");
if (nameLocal == '' || passwordLocal == '') {
alert("您还没注册!");
return;
} if (nameLocal === this.name || passwordLocal === this.password) {
store.dispatch("setLoginUsernameFun", nameLocal);
this.$router.push('/home')
return;
} alert("账号或者密码错误");
},

补充:vueX的五个核心属性

(1)state:

state即Vuex中的基本数据!
state就是用来存放数据,若是对数据进行处理输出,比如数据要过滤,一般我们可以写到computed中。

(2)getters(相当于State的计算属性) :

基础用法:

index.js

const store = new Vuex.Store({
state: {
list: [1, 3, 5, 7, 9, 20, 30]
},
getters: {
filteredList: state => {
return state.list.filter(item => item > 5)
},
listCount: (state, getters) => {
return getters.filteredList.length;
}
}
})

vue中:

<template>

  <div>
过滤后的列表:{{list}}
<br>
列表长度:{{listCount}}
</div>
</template> <script>
export default {
name: "index.vue",
computed: {
list() {
return this.$store.getters.filteredList;
},
listCount() {
return this.$store.getters.listCount;
}
}
}
</script>

(3)mutation(提交更改数据的方法,同步!必须是同步函数)

使用vuex修改state时,有两种方式:
1)可以直接使用 this.$store.state.变量 = xxx;
2)this.$store.dispatch(actionType, payload)或者 this.$store.commit(commitType, payload)
异同点:
1)共同点: 能够修改state里的变量,并且是响应式的(能触发视图更新)
2)不同点:
若将vue创建 store 的时候传入 strict: true, 开启严格模式,那么任何修改state的操作,只要不经过mutation的函数,
vue就会 throw error : [vuex] Do not mutate vuex store state outside mutation handlers。

(4)action(像一个装饰器,包裹mutations,使之可以异步。)

action的功能和mutation是类似的,都是去变更store里的state,不过action和mutation有两点不同:
1)action主要处理的是异步的操作,mutation必须同步执行,而action就不受这样的限制,也就是说action中我们既可以处理同步,也可以处理异步的操作
2)action改变状态,最后是通过提交mutation。

  Action 通过 store.dispatch 方法触发。

(5)modules ( 模块化Vuex):

  在Vue中State使用是单一状态树结构,应该的所有的状态都放在state里面,如果项目比较复杂,那state是一个很大的对象,store对象也将对变得非常大,难于管理。
  modules:可以让每一个模块拥有自己的state、mutation、action、getters,使得结构非常清晰,方便管理

const moduleA = {
state: { ... },
mutations: { ... },
actions: { ... },
getters: { ... }
} const moduleB = {
state: { ... },
mutations: { ... },
actions: { ... }
} const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
}) store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态

2. 打包vue项目并制作成app

  vue-cli3之后的打包与之前不一样,配置文件在vue.config.js中,并且这个文件需要自己创建置于与package.json同目录。关于其配置项可参考:

如果想打包之后静态页面直接点击运行需要将路由改为hash路由:

(1)修改router/index.js

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

(2)vue.config,js修改打包的默认路径:

module.exports = {
publicPath: './',
lintOnSave: false
}

  如果将来我们将页面置于项目中,项目名称为exam,我们将publicPath修改为exam即可。默认是/,./是相对路径。

  lintOnSave: false 是关闭eslint验证(这个验证太烦了)

  接下来到项目根路径运行打包命令即可得到正常的html、css等文件。如下:

E:\HBuilderSpace\vue-demo>npm run build

> vue-demo@0.1.0 build E:\HBuilderSpace\vue-demo
> vue-cli-service build - Building for production... DONE Compiled successfully in 51657ms File Size Gzipped dist\js\chunk-vendors.ae7fcf93.js 125.21 KiB 43.38 KiB
dist\js\app.628ec198.js 7.19 KiB 2.75 KiB
dist\js\about.672d2588.js 1.32 KiB 0.59 KiB
dist\css\about.b0b00f5a.css 0.57 KiB 0.31 KiB
dist\css\app.59544d79.css 0.21 KiB 0.15 KiB

打包后会生成dist目录,并且对文件都进行了压缩,如下:

vue-cli安装以及创建一个简单的项目(二)(vuex使用、发行一个简单的app)

index.html内容如下:(原本是一行,这是我格式化后的。可以看到路径是相对路由)

<!DOCTYPE html>
<html lang=en>
<head>
<meta charset=utf-8>
<meta http-equiv=X-UA-Compatible content="IE=edge">
<meta name=viewport content="width=device-width,initial-scale=1">
<link rel=icon href=favicon.ico>
<title>vue-demo</title>
<link href=css/about.b0b00f5a.css rel=prefetch>
<link href=js/about.672d2588.js rel=prefetch>
<link href=css/app.59544d79.css rel=preload as=style>
<link href=js/app.628ec198.js rel=preload as=script>
<link href=js/chunk-vendors.ae7fcf93.js rel=preload as=script>
<link href=css/app.59544d79.css rel=stylesheet>
</head>
<body>
<noscript><strong>We're sorry but vue-demo doesn't work properly without JavaScript enabled. Please enable it to
continue.</strong></noscript>
<div id=app></div>
<script src=js/chunk-vendors.ae7fcf93.js></script>
<script src=js/app.628ec198.js></script>
</body>
</html>

2.制作一个简单的基于localStorage本地登录的小app

  用vue制作一个简单的基于本地登录的app,基于hash的路由。

1.目录结构:

vue-cli安装以及创建一个简单的项目(二)(vuex使用、发行一个简单的app)

2.附上主要代码:

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

<template>
<div id="app">
<router-view/>
</div>
</template> <style lang="scss">
*{
padding: 0px;
text-align: center;
}
</style>

Main.js

import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store from './store'; 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管理组件定义了一个属性与修改属性的方法

vies/Login.vue

<template>
<div class="login">
<form v-if="!isReg">
<h1>欢迎来到XXX系统</h1>
<br/>
<br/>
<div>用户名: <input type="text" v-model="name"/> </div>
<br/>
<div>密&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;码: <input type="password" v-model="password"/> </div>
<div class="rowBtn" @click="login()">登录</div>
<div class="rowBtn regBtn" @click="reg()">注册</div>
</form>
<form v-else>
<h1>注册</h1>
<br/>
<br/>
<div>用户名: <input type="text" v-model="name"/> </div>
<br/>
<div>密&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;码: <input type="password" v-model="password"/> </div>
<br/>
<div>确认密码: <input type="password" v-model="passwordRepeat"/> </div>
<div class="rowBtn" @click="addUser()">注册</div>
<div class="rowBtn regBtn" @click="cancel()">取消</div>
</form> </div>
</template> <script>
import store from '@/store'; 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("name");
if (nameLocal == '' || passwordLocal == '') {
alert("您还没注册!");
return;
} if (nameLocal === this.name || passwordLocal === this.password) {
store.dispatch("setLoginUsernameFun", nameLocal);
this.$router.push('/home')
return;
} alert("账号或者密码错误");
},
reg() {
this.isReg = true;
},
addUser() {
if (this.name == '' || this.password == '') {
alert("必填用户名密码!!!");
return;
} if (this.password !== this.passwordRepeat) {
alert("两次密码不一致!!!");
return;
} localStorage.setItem("name", this.name);
localStorage.setItem("password", this.password);
this.name = '';
this.password = '';
alert("注册成功!");
this.isReg = false;
},
cancel() {
this.isReg = false;
}
},
};
</script> <style scoped lang="scss">
.rowBtn{
width: 100%;
height: 40px;
font-size: 20px;
text-align: center;
line-height: 40px;
margin-top: 10px;
background: #87CEEB; &.regBtn{
background: #20B2AA;
}
}
</style>

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

views/Home.vue

<template>
<div class="home">
<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;
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>

  定义了两个子路由,并用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>

Contact.vue:

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

3.效果

(1)登录

vue-cli安装以及创建一个简单的项目(二)(vuex使用、发行一个简单的app)

(2)登录之后主页面

vue-cli安装以及创建一个简单的项目(二)(vuex使用、发行一个简单的app)

4.制作成app-利用hbuilder制作app

(1)执行 npm run build 之后生成dist文件。

(2)在hbuilder新建一项目将dist下文件考进去:W表示web项目,A表示APP项目

vue-cli安装以及创建一个简单的项目(二)(vuex使用、发行一个简单的app)

(3)右键dist项目然后选择 转换成移动APP

vue-cli安装以及创建一个简单的项目(二)(vuex使用、发行一个简单的app)

(4)然后发行为原生app即可。之前已经发行过一个mui的app。

  参考:https://www.cnblogs.com/qlqwjy/p/10428546.html

(5)手机端效果如下:

vue-cli安装以及创建一个简单的项目(二)(vuex使用、发行一个简单的app)

补充:项目中引入jquery

1.安装jquery

cnpm install jquery --save-dev

2.vue.config.js头部声明

const webpack = require("webpack")
// vue.config.js
module.exports = {
configureWebpack: {
plugins: [
new webpack.ProvidePlugin({
jQuery: "jquery",
$: "jquery"
})
]
}
}

3.使用的地方引入即可:

import $ from 'jquery'

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