VSCode 关于vue的扩展安装: Vue VSCode Snippets 、Vetur
<div id="app">{{title}}</div>
<script src="./vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data() {
return {
title: 'hello,vue'
}
}
})
setTimeout(() => {
app.title = 'mua~,vue'
},1000);
</script>
理解vue的设计思想
1、数据驱动应用
2、MVVM模式的践行者
MVVM框架的三要素:响应式、模板引擎及其渲染
响应式:vue如何监听数据变化?
模板:vue的模板如何编译和解析
渲染:vue如何将模板转换为html
核心知识03--模板语法
vue模板语法
vue.js使用了基于HTML的模板语法,允许开发者声明式的将DOM绑定到底层Vue实例的数据,所有Vue.js的模板都是合法的HTML,所以能被遵循规范的浏览器和HTML解析器解析。
插值文本
数据绑定最常见的形式就是使用"Mustache"语法(双大括号)的文本插值
范例:设置标题
<div id="app">
<h2>
<!-- 插值文本 -->
{{title}}
</h2>
</div>
<script src="./vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data() {
return {
title: 'hello,vue'
}
}
})
</script>
特性
HTML特性不能使用"Mustache"语法,应该使用v-bind指令
范例-设置标题
<div id="app">
<!-- 特性、属性值绑定使用v-bind指令-->
<h2 v-blind:title="title">...</h2>
</div>
列表渲染
我们可以用v-for指令基于一个数组来渲染一个列表,v-for指令需要使用 item in items形式的特殊语法,其中 items 是源数据结构,而 item 则是被迭代的数组元素的别名。
范例:课程列表
<div id="app">
<!-- 条件渲染 -->
<p v-if="courses.length == 0">没有任何课程信息</p>
<!-- 列表渲染 -->
<ul>
<li v-for="c in courses" :key="c">
{{ c }}
</div>
</ul>
</div>
<script src="./vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data() {
return {
courses: ['web全栈','web高级']
}
}
})
</script>
表单输入绑定
你可以用 v-modal 指令在表单 <input>、<textarea>、及 <select> 元素上创建双向数据绑定。它会根据控件类型自动选择正确的方法来更新元素。 v-modal 本质上是语法糖。它将转换为输入事件以更新数据,并对一些极端场景进行一些特殊处理。
范例:新增课程
<!-- 表单输入绑定 -->
<input v-model="course" type="text" v-on:keydown.enter="addCourse"/>
事件处理
可以用 v-on 指令监听DOM事件,并在触发时运行一些JavaScript代码
范例:新增课程
<!-- 事件处理 -->
<button v-on:click="addCourse">新增课程</button>
<script>
const app = new Vue({
el: '#app',
data() {
return {
course:'',
courses: ['web全栈','web高级']
}
},
methods: {
addCourse() {
this.courses.push(this.course)
this.course = ''
}
},
})
</script>
class与style绑定
操作元素的 class 列表和内联样式是数据绑定的一个常见需求,因为他们都是属性,所以我们可以用 v-bind 处理它们:只需要通过表达式计算出字符串结果即可。不过字符串拼接麻烦且易错。因此,在将 v-bind 用于 class 和 style 时,Vue.js做了专门的增强。表达式结果的类型除了字符串之外,还可以是对象或数组。
<style>
.active{
background-color: #ddd;
}
</style>
<ul>
<!-- class绑定 -->
<li
v-for="c in courses"
:key="c"
:class="{active: (selectedCourse === c)}"
@click="selectedCourse = c">
{{ c }}
</li>
<!-- style绑定 -->
<li
v-for="c in courses"
:key="c"
:style="{backgroundColor: (selectedCourse === c)? '#ddd' : 'transparent'}"
@click="selectedCourse = c">
{{ c }}
</li>
</ul>
<script>
const app = new Vue({
el: '#app',
data() {
return {
// 保存选中项
selectedCourse:''
}
},
})
</script>
计算属性和监听器
模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护,此时就应该考虑计算属性和监听器。
范例:课程数量统计
<p>
<!-- 绑定表达式 -->
<!-- 课程总数:{{courses.length + '门'}} -->
<!-- 计算属性 -->
<!-- 课程总数:{{total}} -->
<!-- 监听器 -->
课程总数:{{totalCount}}
</p>
<script>
const app = new Vue({
el: '#app',
data() {
return {
totalCount:''
}
},
compute: {
total () {
return this.courses.length + '门'
}
},
watch: {
// 下面这种不会生效,因为初始化时不会触发
courses(newValue, oldValue) {
this.totalCount = newValue.length + '门'
}
},
watch: {
// 这种方式会在初始化时触发
courses: {
immediate: true,
deep: true,
handler(newValue, oldValue) {
this.totalCount = newValue.length + '门'
}
}
},
})
</script>
计算属性 VS 监听器
1、监听器更通用,理论上计算属性能实现的监听器也能实现
2、处理数据的场景不同,监听器适合一个数据影响多个数据,计算属性适合一个数据受多个数据影响
3、计算属性有缓存行,计算所得的值如果没有变化不会重复执行
4、监听器适合执行异步操作或比较大开销操作的情况
神奇的模板语法是如何实现的
在底层的实现上,Vue将模板编译成虚拟DOM渲染函数,结合响应系统,Vue能够智能地计算出最少需要重新渲染多少组件,并把DOM操作次数减到最少。
// 输出vue替我们生成的渲染函数一窥究竟
console.log(app.$options.render)
//它长这个样子
(functionanonymous(
){
with(this){return_c('div',{attrs:{"id":"app"}},[_c('h2',{attrs:
{"title":title}},[_v("\n"+_s(title)+"\n")]),_v("
"),_c('input',{directives:[{name:"model",rawName:"v-model",value:
(course),expression:"course"}],attrs:{"type":"text"},domProps:{"value":
(course)},on:{"keydown":function($event)
{if(!$event.type.indexOf('key')&&_k($event.keyCode,"enter",13,$event.key,"Enter"
))returnnull;returnaddCourse($event)},"input":function($event)
{if($event.target.composing)return;course=$event.target.value}}}),_v("
"),_c('button',{on:{"click":addCourse}},[_v("新增课程")]),_v(""),(courses.length
==0)?_c('p',[_v("没有任何课程信息")]):_e(),_v("
"),_c('ul',_l((courses),function(c){return_c('li',{class:{active:
(selectedCourse===c)},on:{"click":function($event){selectedCourse=c}}},
[_v(_s(c))])}),0)])}
})
结论:Vue通过它的编译器将模版编译成渲染函数,在数据发生变化时的时候再次执行渲染函数,通过对比两次执行结果得出要做的dom操作,模版中的魔法得以实现。
生命周期
每个Vue实例在创的时候都要经过一系列的初始化过程--例如,需要设置数据监听, 编译模板, 将实例挂载到DOM并在数据变化时更新DOM等, 称为Vue示例的生命周期
使用生命周期钩子
在Vue实例的生命周期过程中会运行一些叫做生命周期钩子的函数, 这给用户在不同阶段添加自己代码的机会.
范例: 异步获取课程列表
<script>
// 模拟异步数据调用接口
function getCourses(){
return new Promise(resolve => {
setTimeout(() => {
resolve(['web全栈','web高级'])
}, timeout);
})
}
const app = new Vue({
el: '#app',
data() {
return {
courses:[],
}
},
// created钩子中调用接口
async created () {
const courses = await getCourses();
this.courses = courses;
}
})
</script>
生命周期结论:
三个阶段: 初始化 更新 销毁
初始化: beforeCreate created beforeMount mounted
更新: beforeUpdate updated
销毁: beforeDestroy destroyed
使用场景分析:
{
beforeCreate(){} // 执行时组件实例还未创建, 通常用于插件开发中执行一些初始化任务
created(){} // 组件初始化完毕, 各种数据可以使用, 通常用于异步数据获取
beforeMount(){} // 未执行渲染, 更新, dom未创建
mounted(){} // 初始化结束, dom已创建, 可用于获取访问数据和dom元素
beforeUpdate(){} // 更新前, 用于获取更新前各种状态
updated(){} // 更新后, 所有状态已是最新
beforeDestroy(){} // 销毁前, 可用于一些定时器或订阅的取消
destroyed(){} // 组件已销毁,作用同上
}
组件化
组件是可复用的Vue实例,带有一个名字,我们可以在一个通过new Vue 创建的Vue根实例中,把这个组件作为自定义元素来使用.
组件注册、使用以及数据传递
Vue.component(name, options) // 可用于组件注册
范例: 提取课程新增和课程列表组件
<!-- 列表渲染 -->
<course-list :courses="courses"></course-list>
<script>
// 注册course-list组件
Vue.component('course-list',{
data() {
return {
selectedCourse: ''
}
},
props: {
courses: {
type: Array,
default: []
},
},
template: `
<div>
<!-- 条件渲染 -->
<p v-if="courses.length === 0">没有任何课程信息</p>
<!-- 列表渲染 -->
<ul>
<!-- class绑定 -->
<li
v-for="c in courses"
:key="c"
:class="{active: (selectedCourse === c)}"
@click="selectedCourse = c">
{{ c }}
</li>
</ul>
</div>
`
})
const app = new Vue({
el: '#app',
data() {
return {
courses: ['web全栈','web高级'],
}
}
})
</script>
自定义事件及其监听
当子组件需要和父组件进行通信, 可以派发并监听自定义事件
范例: 新增课程组件派发新增事件
<!-- 课程添加组件调用 -->
<course-add @add-course="addCourse"></course-add>
// 注册course-add组件
Vue.component('course-add', {
data() {
return {
course: '', // 将course从父组件提取到course-add维护
}
},
template: `
<div>
<!-- 表单输入绑定 -->
<input v-model="course" @keydown.enter="addCourse"/>
<!-- 事件处理 -->
<button v-on:click="addCourse">新增课程</button>
</div>
`,
methods: {
// 回调函数接收事件参数
addCourse() {
// 发送自定义事件通知父组件
// 注意事件名称定义时不要有大写字母出现
this.$emit('add-course', this.course )
this.course = ''
}
}
})
const app = new Vue({
el: '#app',
data() {
return {
courses: ['web全栈','web高级'],
}
},
methods: {
addCourse(course) {
this.courses.push(course)
}
}
})
在组件上使用v-modal
范例: 改造course-add为支持v-modal的版本
<!-- 自定义组件支持v-modal需要实现内部的input的:value和@input -->
<course-add v-modal="course" @add-course="addCourse"></course-add>
<script>
// 注册course-add组件
Vue.component('course-add', {
props:['value'],
template: `
<div>
<!-- 需要实现input的:value和@input -->
<input :value="value" @input="onInput" @keydown.enter="addCourse"/>
<!-- 事件处理 -->
<button v-on:click="addCourse">新增课程</button>
</div>
`,
methods: {
addCourse() {
// 派发事件不再选哟传递数据
this.$emit('add-course', this.course )
},
onInput (e) {
this.$emit('input', e.target.value)
}
},
})
const app = new Vue({
el: '#app',
data() {
return {
course:'', // 还原course
// 保存选中项
selectedCourse:'',
courses: ['web全栈','web高级'],
totalCount:''
}
},
methods: {
addCourse() {
this.courses.push(this.course)
}
},
})
</script>
v-model 默认转换是:value和@input, 如果想要修改这个行为, 可以通过定义model选项
Vue.component('course-add', {
model: {
prop:'value',
event: 'change'
}
})
通过插槽分发内容
通过使用vue提供的 <slot> 元素可以给组件传递内容
范例:弹窗组件
<style>
.message-box{
padding: 10px 20px;
background: #4fc08d;
border: 1px solid #42b983;
}
.message-box-close {
float: right;
}
</style>
<!-- 插槽实现内容分发 -->
<message :show.sync="show" @update-show="updateShow">新增课程成功!</message>
<script>
// 注册message组件 slot做为占位符
Vue.component('message', {
props: ['show'],
template: `
<div class="message-box" v-if="show">
<slot></slot>
<span class="message-box-close" @click="$emit('update-show', false)">X</spam>
</div>
`
})
const app = new Vue({
el: '#app',
data() {
return {
show: false, // 提示框状态
course:'', // 还原course
// 保存选中项
selectedCourse:'',
courses: ['web全栈','web高级'],
totalCount:''
}
},
methods: {
// 还原addCourse
addCourse() {
this.courses.push(this.course)
// 提示框新增信息
this.show = true
},
updateShow (bool) {
this.show = bool;
}
},
})
</script>
如果存在多个独立内容要分发,可以使用具名插槽v-slot:name
范例: 添加一个title部分
<!-- 插槽实现内容分发 -->
<message :show.sync="show" @update-show="updateShow">
<template v-slot:title>恭喜</template>
<template>新增课程成功!</template>
</message>
// 注册message组件 slot做为占位符
Vue.component('message', {
props: ['show'],
template: `
<div class="message-box" v-if="show">
<strong><slot name="title"></slot/></strong>
<slot></slot>
<span class="message-box-close" @click="$emit('update-show', false)">X</spam>
</div>
`
})
Vue组件化的理解3
组件化是Vue的精髓,Vu而英勇就是由一个个组件构成的, Vue的组件化设计到的内容非常多, 可以从一下几点进行阐述.
定义: 组件是可复用的Vue实例, 准确讲它们是VueComponent的实例, 继承自Vue
优点: 从上面案例可以看出组件化可以增加代码的复用性、 可维护性、和可测试行
使用场景: 什么时候使用组件?以下分类可作为参考
1、通用组件: 实现最基本的功能, 具有通用性 复用性, 例如按钮组件、输入框组件、布局组件等
2、业务组件: 它们完成具体业务, 具有一定的复用性, 例如登陆组件, 轮播图组件
3 、页面组件: 组织应用各部分独立内容, 需要时在不同页面组件间切换, 例如列表页, 详情页组件
如何使用组件
1、 定义: Vue.component() 、 comonents选项、sfc
2、分类: 有状态组件, functional 、 abstract
3、 通信 props、$emit() / $on()、 provide/inject、 $children / $parent/、 $root、 $attrs、 $listeners
4、内容分发: <slot>, <template>, v-slot
5、 使用及优化: is, keep-alive, 异步组件
组件的本质
vue中的组件经理如下过程
组件配置 => Vu二Component实例 => render() => Virtual DOM => DOM
拓展知识--可复用性
过滤器
Vue.js允许你自定义过滤器,可被用于一些常见的文本格式化。过滤器可以用在两个地方:双花括号插值和v-bind表达式。过滤器应该被添加在JavaScript表达式的尾部,由"管道"符号指示
<!-- 双花括号中 -->
{{ message | capitalize }}
<!-- v-bind 中-->
<div v-bind:id="rawId | formatId"></div>
范例:货币符号使用
<div id="app">
<h2>Web 开发工程师最低薪资是 {{ number | currency('¥') }}</h2>
</div>
<script>
const app = new Vue({
el: '#app',
data() {
return {
number: 10000
}
},
filters: {
currency (value, symbol = '$') {
return symbol + value;
}
}
})
</script>
自定义指令
除了核心功能默认内置的指令(v-modal 和 v-show),Vue也允许自定义指令。注意,在Vue2.0中,代码复用和抽象的主要形式是组件。然而,有的情况下,你仍然要对普通DOM元素进行底层操作,这时候就会用到自定义指令
范例:输入框获取焦点
directives/focus.js
export default {
directiveName: 'focus',
options: {
inserted(el) {
el.focus();
}
}
}
directives/permision.js
export default {
directiveName: 'permision',
options: {
inserted(el,binding) {
if (binding.value !== 'admin') {
el.parentElement.removeChild(el);
}
}
}
}
directives/index.js
import focus from './focus';
import permision from './permision';
export default {
focus,
permision
}
main.js
import Vue from 'vue'
import App from './App.vue'
// 自定义指令
import directives from './directives'
Vue.config.productionTip = false
Vue.prototype.$bus = new Vue()
const { focus, permision } = directives
// 获取焦点自定义指令
Vue.directive(focus.directiveName, focus.options)
// 权限自定义指令
Vue.directive(permision.directiveName, permision.options)
new Vue({
render: h => h(App),
}).$mount('#app')
CourseAdd.vue
<!-- 表单输入绑定 -->
<input v-model="course" type="text" v-on:keydown.enter="addCourse" @input="onInput" v-focus/>
DirectiveBtn.vue
<template>
<div v-permision="'user'">
<button>自定义指令按钮</button>
</div>
</template>
Vue.set 、Vue.delete 响应式数据添加删除
Vue.set: 向响应式数据中添加一个属性,并确保这个新的响应式数据同样是相应式的,且触发视图更新。使用方法:Vue.set(target, propertyName/index, value)
范例:设置商品价格
<template>
<div>
<!-- 添加批量加格更新 -->
<p>
<input type="text" v-model.number="price">
<button @click="batchUpdate">批量更新价格</button>
</p>
<ul>
<!-- class绑定 -->
<li
v-for="c in courses"
:key="c"
:class="{active: (selectedCourse === c)}"
@click="selectedCourse = c">
{{ c.name }} - ¥{{c.price || 0}}
</li>
<!-- style绑定 -->
<!-- <li
v-for="c in courses"
:key="c"
:style="{backgroundColor: (selectedCourse === c)? '#ddd' : 'transparent'}"
@click="selectedCourse = c">
{{ c }}
</li> -->
</ul>
</div>
</template>
<script>
export default {
props: {
courses: {
type: Array,
required: true,
default: function () {
return []
}
},
},
data() {
return {
// 保存选中项
selectedCourse:'',
price: 0 // 增加加格数据
}
},
methods:{
batchUpdate(){
this.courses.forEach(course => {
this.$set(course, 'price', this.price)
})
}
}
}
</script>
<style scoped>
.active{
background-color: #ddd;
}
</style>
Vue.delete
删除对象的属性。如果对象是响应式的,确保删除能触发更新视图
使用方法:Vue.delete(target, property/index)
Vue事件总线 $bus
通过在Vue原型上添加一个Vue实例作为事件总线,实现组件之间相互通信,而且不受组件之间关系的影响
Vue.prototype.$bus = new Vue()
范例:关闭消息框
Message.vue
<template>
<div class="message-box" v-if="show">
<strong><slot name="title"></slot></strong>
<slot></slot>
<span class="message-box-close" @click="$emit('update-show', false)">X</span>
</div>
</template>
<script>
export default {
props: ['show'],
mounted () {
this.$bus.$on('message-close', () => {
this.$emit('update-show', false)
});
},
}
</script>
<style scoped>
.message-box{
padding: 10px 20px;
background: #4fc08d;
border: 1px solid #42b983;
}
.message-box-close {
float: right;
cursor: pointer;
}
</style>
ClearMessage.vue
<template>
<button class="toolbar" @click="clearMessage">
清空提示框
</button>
</template>
<script>
export default {
name: 'ClearMessage',
methods:{
clearMessage(){
// 派发关闭事件
this.$bus.$emit('message-close', false)
}
},
}
</script>
<style lang="scss" scoped>
</style>
main.js
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
Vue.prototype.$bus = new Vue()
new Vue({
render: h => h(App),
}).$mount('#app')
vm.$once
监听一个自定义事件,但是只触发一次。一旦出发之后,监听器就会被移除。
vm.$once('test', function(msg) {
console.log(msg)
})
vm.$off
移除自定义事件监听器
1、如果没有提供参数,则移除所有的事件监听器
2、如果只提供了事件,则移除该是按所有的监听器
3、如果同时提供了事件与回调,则只移除这个回调的监听器
vm.$off() // 移除所有的事件监听器
vm.$off('test') // 移除该事件所有的监听器
vm.$off('test', callback) // 只移除这个回调的监听器
ref、vm.
$refs
组件或元素引用:ref和vm.$refs, ref被用来给元素或子组件注册引用信息,引用信息将会注册在父组件的$refs对象上。如果在普通的DOM元素上使用,引用指向的就是DOM元素;如果用在子组件上,引用就指向该子组件
<input type="text" ... ref="inp">
mounted(){
// mounted之后才能访问到inp
this.$refs.inp.focus()
}
范例:改造message组件用打开、关闭方法控制显示
<!--自定义组件引用-->
<message ref="msg">新增课程成功!</message>
<script>
Vue.component('message', {
// 组件显示状态
data() {
return {
show: false
}
},
template: ` <div class="message-box" v-if="show">
<slot></slot>
<!--toggle内部修改显示状态-->
<span class="message-box-close" @click="toggle">X</span>
</div> `,
// 增加toggle方法维护toggle状态
methods: {
toggle() {
this.show = !this.show;
}
},
// 修改message-close回调为toggle
mounted () {
this.$bus.$on('message-close', this.toggle);
},
})
const app = new Vue({
methods: {
addCourse() {
// 使用$refs.msg访问自定义组件
this.$refs.msg.toggle()
}
}
})
</script>
注意:
1、ref是作为渲染结果被创建的,在初始渲染时不能访问它们
2、$refs不是响应式的,不要试图用它在模板中做数据绑定
3、当v-for用于元素或组件时,引用信息将是包含DOM节点或组件实例的数组
Vue-cli
快速原型开发----可以使用 vue server 和 vue build 命令对单个.vue文件进行快速原型开发
安装:
npm install -g @vue/cli-service-global
准备一个原型内容---- vue serve ------ 启动一个服务并运行原型----- vue serve hello.vue
vue serve hello.vue
要求:vue-cli须在4.x
vuec-cli升级
npm uninstall -g vue-cli // 卸载
npm install -g @vue/cli
npm list -g --depth 0 // 查看npm全局安装模块详细信息
Vuex
Vuex是一个专为Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以可预测的方式发生变化。
安装
vue add vuex
1、state: 应用全局状态定义在state中
2、mutation:修改state只能通过mutation
3、action:类似于mutation,不同在于action提交的是mutation,而不是直接变更状态,action可以包含任意异步操作
4、getter:可以使用getters从store的state中派生出一些状态
5、插件:Vuex的store接受plugins选项,这个选项暴漏出每次mutation的钩子。Vuex插件就是一个函数,它接收store作为唯一参数
vuex相关文件:
main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import focus from './directives/focus'
import store from './store'
import './plugins/element.js'
Vue.config.productionTip = false
Vue.prototype.$bus = new Vue()
Vue.directive('focus', focus)
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import user from './user'
import persist from './plugins/persist'
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
user
},
strict: true,
plugins: [persist]
})
/store/user.js
import {addAuthRoute} from '@/router/index'
export default {
namespaced: true, // 设置独立命名空间,避免命名冲突
state: {
isLogin: false,
username: ''
},
mutations: {
login(state, username) {
state.isLogin = true
state.username = username
},
logout(state) {
state.isLogin = false
state.username = ''
},
},
getters: {
welcome: state => state.username + ',欢迎回来'
},
actions: {
// 参数1是vuex传递的上下文context:{commit, dispatch, state}
login({ commit }, username) {
// 模拟登录api调用,1s钟以后如果用户名是admin则登录成功
return new Promise((resolve, reject) => {
setTimeout(() => {
if (username === 'admin') {
commit('login', username)
// 动态添加认证路由
addAuthRoute()
resolve()
} else {
reject()
}
}, 1000);
})
}
}
}
/store/plugins/persist.js 实现登录状态持久化
export default store => {
// store初始化的时候,将存储在localStoreage中的状态还原
if (localStorage) {
const user = JSON.parse(localStorage.getItem('user'))
if (user) {
store.commit('user/login', user.username)
}
}
// 如果用户相关状态发生变化,自动存入localStoreage
store.subscribe((mutation, state) => {
// {type:'user/login'}
// {type:'user/logout'}
// {type:'cart/addCart'}
if(mutation.type === 'user/login') {
const user = JSON.stringify(state.user)
localStorage.setItem('user', user)
} else if (mutation.type === 'user/logout') {
localStorage.removeItem('user')
}
})
}
mapState、mapMutations、mapActions、mapGetters使用
login.js
<template>
<div>
<button @click="login" v-if="!isLogin">登录</button>
<button @click="logout" v-else>注销</button>
<p>{{welcome}}</p>
</div>
</template>
<script>
import {mapState, mapGetters, mapMutations, mapActions} from 'vuex'
export default {
methods: {
login() {
// window.isLogin = true;
// 提交mutation变更状态
// this.$store.commit('user/login')
// 派发动作,触发actions
// this.$store.dispatch("user/login", "admin").then(() => {
this["user/login"]("admin").then(() => {
this.$router.push(this.$route.query.redirect);
}).catch(() => {
alert('用户名或密码错误,请重试!')
});
this.LOGIN("admin")
},
logout() {
// window.isLogin = false;
this.$store.commit("user/logout");
this.$router.push("/");
},
...mapMutations('user',{LOGIN:'login',LOGOUT:'logout'}),
...mapActions(['user/login', 'user/logout'])
},
computed: {
// isLogin() {
// return this.$store.state.user.isLogin;
// }
...mapState('user', ['isLogin']),
...mapGetters('user',['welcome'])
}
};
</script>
<style lang="scss" scoped>
</style>