2019年实习时的 VueJS基础知识 备份
介绍
- Vue 是一套用于构建用户界面的渐进式框架,数据驱动视图,只关注视图层,采用自底向上增量开发的设计。
使用方式
代码语言:javascript复制// 原生引入
<script src="vue.min.js"></script>
开发规范
- 组件名为多个单词
- 私有 property 名使用 $_ 前缀,并附带一个命名空间以避免冲突。
- 单文件组件的文件名始终单词大写开头,或者横线链接。
- 特定样式和约定组件全部以一个特定的前缀开头
- 和父组件紧密耦合的子组件应该以父组件名作为前缀命名
- 组件名倾向完整单词,避免缩写。
生命周期
基本顺序
创建→挂载→更新→销毁
具体步骤
State | Description |
---|---|
beforeCreate | 创建前:此阶段为实例初始化,此时的数据观察和事件机制都未形成,不能获得 DOM 节点。 |
created | 创建后:实例初始化完毕,页面还没开始渲染,但可以操作数据(data,prop,发送请求获取数据)。 |
beforeMount | 挂载前:在这一阶段,我们虽然依然得不到具体的 DOM 元素,但 vue 挂载的根节点已经创建,之后对 DOM 的操作将围绕这个根元素继续进行,这个阶段是过渡性的,一般一个项目只能用到一两次。 |
mounted | 挂载后:在这个阶段,数据和 DOM 都已被渲染。 |
beforeUpdate | 更新前:这一阶段遵循数据驱动 DOM 的原则,函数在数据更新后虽然没立即更新数据,但是 DOM 中的数据会改变 |
updated | 更新后:在这一阶段 DOM 会和更改过的内容同步。 |
beforeDestroy | 销毁前:在上一阶段 vue 已经成功的通过数据驱动 DOM 更新,当我们不再需要 vue 操纵 DOM 时,就要销毁 vue ,也就是清除 vue 实例与 DOM 的关联,调 destroy 方法可以销毁当前组件,在销毁前会触发 beforeDestroy 钩子函数。(此时记得解除绑定事件,销毁定时器与全局变量等等。) |
destroyed | 销毁后:在销毁后,会触发 destroyed 钩子函数。 |
- 生命周期图示
父子组件执行顺序
- 加载渲染过程
父beforeCreate→父created→父beforeMount→子beforeCreated→子created→子beforeMount→子mounted→父mounted
- 更新过程
父beforeUpdate→子beforeUpdate→子updated→父updated
- 销毁过程
父beforeDestroy→子beforeDestroy→子destroyed→父destroyed
常用指令
v-text 文本填充
示例:
代码语言:javascript复制<span v-text="msg"></span>
<!--{{ 双大括号也会将数据解释为纯文本 }}-->
v-html html填充
示例:
代码语言:javascript复制<div v-html="rawHtml"></div>
v-bind 动态地绑定一个或多个特性,或一个组件 prop 的表达式。
示例:
代码语言:javascript复制<div id="app">
<!--当data里面定义的isActive等于true时,is-active这个类才会被添加起作用-->
<!--当data里面定义的hasError等于true时,text-danger这个类才会被添加起作用-->
<!--也可以写表达式:例如三元运算符等等-->
<div :class="{'is-active':isActive, 'text-danger':hasError}"></div>
</div>
<!--其他写法-->
<!--<单个类可写 :class="{'bg-danger text-light':true}">-->
<!--<多个类可写 :class="{'bg-danger text-light':true}">-->
<div :class="xxx == xxxxx ? 'bg-danger' : 'bg-light'">
<span :class="['message-item-user', {'order-last': xxx == xxxxx}, {xxx == xxxxx ? 'bg-danger' : 'bg-light'}]">{{ message }}</span>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
isActive: true,
hasError: false
}
});
</script>
v-on 用于监听指定元素的 DOM 事件,绑定事件监听器。
- 常用 v-on 事件
Name | Description | Name | Description |
---|---|---|---|
click | 点击元素 | mouseenter | 鼠标移入元素 |
dbclick | 双击元素 | mouseleave | 鼠标移出元素 |
focus | 元素获得焦点 | mousemove | 鼠标在元素内移动 |
blur | 元素失去焦点 | mousedown | 在元素上按下鼠标 |
keydown | 按下键盘 | mouseup | 在元素上释放鼠标 |
keyup | 释放键盘 | submit | 提交元素 |
input | 在元素内输入内容 | scroll | 滚动元素 |
示例:
代码语言:javascript复制<div id="app">
<button @click="consoleLog"></button>
</div>
<script>
var app = new Vue({
el: '#app',
methods: {
consoleLog: function (event) {
console.log(1);
}
}
});
</script>
v-model 实现表单输入和应用状态之间的双向绑定。
示例:
原理:<input type="text" :value="datax" @input="datax = $event.target.value">
<div id="app">
<input v-model.trim="somebody">
<p>hello {{somebody}}</p>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
somebody: 'world'
}
});
</script>
v-for 循环遍历,基于一个数组或者对象渲染一个列表。
示例:
代码语言:javascript复制有以下两种遍历方式
<div v-for="(item,index) in items"></div> //使用in,index是一个可选参数,表示当前项的索引。
<div v-for="item of items"></div>//使用of。
//遍历对象时是按照Object.keys()的顺序进行遍历,即ascii顺序。
v-if 根据表达式的值的真假条件渲染元素
示例:
代码语言:javascript复制<div v-if="ok">yes</div>
v-else 搭配v-if使用
示例:
代码语言:javascript复制<div v-if="ok">yes</div>
<div v-else>No</div>
v-show 根据表达式的真假值展示元素
示例:
代码语言:javascript复制<h1 v-show="ok">hello world</h1>
v-pre 跳过这个元素和它的子元素的编译过程
示例:
代码语言:javascript复制<div id="app">
<span v-pre>{{message}}</span> //这条语句不进行编译
<span>{{message}}</span>
</div>
v-once 只渲染元素和组件一次
示例:
代码语言:javascript复制<span v-once>This will never change:{{msg}}</span> //单个元素
<div v-once>//有子元素
<h1>comment</h1>
<p>{{msg}}</p>
</div>
<my-component v-once:comment="msg"></my-component> //组件
<ul>
<li v-for="i in list">{{i}}</li>
</ul>
常用于处理 DOM 事件的事件修饰符
Instructions | Description |
---|---|
.stop | 阻止事件继续传播 |
.prevent | 事件不再重载页面 |
.capture | 使用事件捕获模式,即元素自身触发的事件先在此处处理,然后才交由内部元素进行处理。 |
.self | 只当在 event.target 是当前元素自身时触发处理函数 |
.once | 事件将只会触发一次 |
.passive | 告诉浏览器你不想阻止事件的默认行为 |
@keyup.enter.native="toNextInput"
常用按键绑定
常用属性
- el:指示 vue 编译器从什么地方开始解析 vue 语法,相当于一个占位符。
- data:组织从 view 中抽象出来的属性,将视图的数据抽象出来存放在 data 中。
- template:设置模板,可以用于替换页面元素。
- method:放置页面中的业务逻辑,js 方法一般都放在 method 中。
- render:创建真正的 Virtual Dom。
- computed:根据已经存在的属性计算出新的属性,对于相同的数据会缓存,当依赖的属性值发生变化时,这个属性的值也会自动更新。
- watch:监听 data 中的数据变化。
过滤器
- 在两个大括号中
{{message | capitalize}}
- 在 v-bind 指令中
v-bind:id="rawId | formatId"
- 串联
{{message | filterA | filter}}
- 接受参数
{{message | filterA('arg1',arg2)}}
计算属性和监听器
计算属性
- computed
- 属性默认只有 getter,不过在需要的时候也可以提供一个 setter。
- computed 和 methods 的区别:computed 是基于依赖缓存,只有相关依赖发生改变时才会重新取值。methods 是在重新渲染的时候,函数总会重新调用执行。
示例:
代码语言:javascript复制<template>
<div id="app">
<div>first: {{first}}</div>
<div>last: {{last}}</div>
<div>result: {{result}}</div>
<button @click="onclick">更改</button>
</div>
</template>
<script>
export default {
data() {
return{
first: 10,
ast: 10
}
},
computed: {
result: {
// 监听 data 中的 first 和 last, 得到新变量 result。
// 注意:只有当值改变时才会执行。
get() {
return this.first this.last;
},
// set方法作用:通过参数修改计算的依赖属性 first 和 last 值
set(newValue) {
this.first = newValue;
this.last = newValue;
}
}
},
methods: {
onclick() {
// 调用计算属性的 set 方法,修改 first 和 last 的值。
this.result = 15;
}
}
}
</script>
监听属性
- watch 实时监听数据变化并改变自身的值。
- 允许执行异步操作,限制执行该操作频率。
示例:
代码语言:javascript复制watch: {
value(newVal, oldVal) {
if (newVal != oldVal) {
this.sum = newVal;
} else {
console.log(newVal, oldVal);
}
}
computed/watch 区别
computed
- 支持缓存,只有依赖数据发生改变,才会重新进行计算。
- 不支持异步,当 computed 内有异步操作时无效,无法监听数据的变化。
- computed 属性值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于 data 中声明过或者父组件传递的 props 中的数据通过计算得到的值。
- 如果一个属性是由其他属性计算而来的,这个属性依赖其他属性,是一个多对一或者一对一,一般用 computed
- 如果 computed 属性属性值是函数,那么默认会走 get 方法,函数的返回值就是属性的属性值。在 computed 中的,属性都有一个 get 和一个 set 方法(自己配置),当数据变化时,调用 set 方法。
watch
- 不支持缓存,发生改变,直接会触发监听事件。
- watch 支持异步;
- 监听的函数接收两个参数,第一个参数是最新的值,第二个参数是输入之前的值。
- 当一个属性发生变化时,需要执行对应的操作。
- 监听数据必须是data中声明过或者父组件传递过来的 props 中的数据,当数据变化时,触发其他操作,函数有两个参数:
- immediate:组件加载立即触发回调函数执行。
- deep:深度监听,为了发现对象内部值的变化,复杂类型的数据时使用,例如数组中的对象内容的改变(监听数组的变动不需要这么做)。注意:Vue 2 中 deep 无法监听到数组的变动和对象的新增,参考 Vue 数组更新检测,只有以响应式的方式触发才会被监听到。
响应式原理
- 官方文档介绍如下
当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data
选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty
把这些 property 全部转为 getter/setter。Object.defineProperty
是 ES5 中一个无法 shim 的特性,这也就是 Vue 不支持 IE8 以及更低版本浏览器的原因。
这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在 property 被访问和修改时通知变更。这里需要注意的是不同浏览器在控制台打印数据对象时对 getter/setter 的格式化并不同,所以建议安装 vue-devtools 来获取对检查数据更加友好的用户界面。
每个组件实例都对应一个 watcher
实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。
- 博主 BB
Vue 2
文档中提到:由于 JavaScript 的限制,Vue 不能检测数组和对象的变化。尽管如此我们还是有一些办法来回避这些限制并保证它们的响应性。
其实出现这个问题的主要原因就是 Object.defineProperty
,因为 Object.defineProperty
是采用数据劫持的方式进行数据监听,即必须提供监听数据的 key
,才能进行数据拦截并监听,但是数组对象是变化的,所以存在这个缺陷。而 ES6 中的 Proxy
,是通过直接代理数据的方式进行监听,所以没有此问题。
另外 Vue 3
中,Object.defineProperty
已改用为 ES6 Proxy
。官方文档说明,当我们从一个组件的 data
函数中返回一个普通的 JavaScript 对象时,Vue 会将该对象包裹在一个带有 get 和 set
处理程序的 Proxy
中。Proxy
是在 ES6 中引入的,它使 Vue 3
避免了 Vue 早期版本中存在的一些响应性问题。
虚拟 DOM
前面响应式原理中有提到虚拟 DOM(Virtual DOM),那么如何理解它呢?
虚拟 DOM 其实就是用普通 JavaScript 对象来描述 DOM 结构,因为不是真实DOM,所以称之为虚拟 DOM。
虚拟 DOM 是相对于浏览器所渲染出来的真实 DOM 而言的,在 React/Vue
等技术出现之前,我们要改变页面展示的内容只能通过遍历查询 DOM 树的方式找到需要修改的 DOM 然后修改样式行为或者结构,来达到更新页面的目的。
DOM 树的实现模块和 JavaScript 模块是分开的,这些跨模块的通讯增加了资源耗费成本,而且这种方式操作会引起浏览器的回流和重绘,使得性能开销巨大,同时每次查询 DOM 几乎都需要遍历整颗 DOM 树。
但若建立一个与 DOM 树对应的虚拟 DOM 对象( JavaScript 对象),以对象嵌套的方式来表示 DOM 树及其层级结构,那么每次 DOM 的更改就变成了对 DOM 对象的属性的增删改查,这样一来查找 JavaScript 对象的属性变化要比查询 DOM 树的性能开销小。
所以 React/Vue 都采用虚拟 DOM 的方式来渲染页面,当监测页面触发了渲染事件或者数据变化后,会重新生成一个新的虚拟 DOM,然后对比新旧虚拟 DOM 进行渲染,至于渲染方案与生成方案需要自己去了解啦。
nextTick
将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。它跟全局方法 Vue.nextTick 一样,不同的是回调的 this 自动绑定到调用它的实例上。
因为 Vue 实现响应式并不是数据发生变化之后 DOM 立即变化,所以若要在视图更新之后,基于新的视图进行操作,则需要用到 nextTick。
- 使用
this.testText = '更新后文本';
let text = document.getElementById("changeDom").innerHTML;
console.log(text); // '更新前文本'
/* ------------------------------ */
this.testText = '更新后文本';
this.$nextTick(function () {
let text = document.getElementById("changeDom").innerHTML;
console.log(text); // '更新后文本'
});
组件
组件的定义使用
示例:
代码语言:javascript复制//定义一个 <vue-demo> 组件
Vue.component('vue-demo', {
data: function () {
//do something
},
//设置显示模板
template: ''
});
//使用 <vue-demo> 组件
//HTML 文件中引入使用
<div id="app">
<vue-demo></vue-demo>
</div>
//JS 文件中初始化
new Vue({ el: '#app' });
父子组件的传值方式
- props/$emit
- 父组件传值给子组件:父组件通过一个属性,将其 data 上的值于该属性进行绑定,子组件通过 props 接受这个属性,就能获取这个属性的值。
- 子组件传值给父组件:子组件通过实践触发的方式向父组件传值,当子组件的数值发生变化时,向外发射一个事件,然后父组件监听该事件名称,并在父组件的 data中去定义这个函数名的函数体
- 注册组件
- 全局组件:所有实例都能使用。
- 局部组件:只能在实例的选项中使用。
- Prop。
- Prop 验证:type 可以是原生构造器,也可以是自定义构造器。
- 自定义事件。
- 父组件使用 props 传递数据给子组件,子组件将数据传递回去则需要使用到自定义事件。
- 使用 v-on 绑定自定义事件,每个 Vue 实例都实现了事件接口(Events interface)。
- 父组件可以在使用子组件的地方直接用 v-on 监听子组件触发的事件。
- children/parent
- provide/inject
- $refs
- eventBus 思否、知乎
- Vuex
- html5Storage
- attrs/listeners
props/methods/data/computed/watch 优先级
代码语言:javascript复制// 通过 srccoreinstanceinit.js 源码
export function initState (vm: Component) {
vm._watchers = []
const opts = vm.$options
if (opts.props) initProps(vm, opts.props)
if (opts.methods) initMethods(vm, opts.methods)
if (opts.data) {
initData(vm)
} else {
observe(vm._data = {}, true /* asRootData */)
}
if (opts.computed) initComputed(vm, opts.computed)
if (opts.watch && opts.watch !== nativeWatch) {
initWatch(vm, opts.watch)
}
}
我们可以看到优先级是
props > methods > data > computed > watch
自定义指令
除了默认设置的核心指令( v-model 和 v-show),Vue 也允许注册自定义指令。
钩子函数
Funtion | Description |
---|---|
bind | 只调用一次,指令第一次绑定到元素时调用. |
inserted | 被绑定元素插入父节点时调用 |
update | 被绑定元素所在的模板更新时调用 |
componentUpdated | 被绑定元素所在模板完成一次更新周期时调用 |
unbind | 只调用一次,指令与元素解绑时调用。 |
钩子函数参数
Parameter | Description |
---|---|
el | 指令所绑定的元素,可以直接用来操作 DOM。 |
binding | 一个对象 |
vnode | Vue 编译生成的虚拟节点 |
oldVnode | 上一个虚拟节点,仅在 update 和 componentUpdateed 中可用。 |
binding属性
Attribute | Description |
---|---|
name | 指令名 |
value | 指令的绑定值 |
oldValue | 指令绑定的前一个值 |
expression | 绑定值的表达式或变量名 |
arg | 传给指令的参数 |
modifiers | 一个包含修饰符的对象 |
路由(Route)
router-link 是一个用于设置一个导航链接的组件,实现路由的跳转。
相关属性
Attribute | Description |
---|---|
to | 目标路由的链接 |
replace/push | 调用 router.replace(),导航后不会留下 history 记录。 |
append | 在当前(相对)路径前添加其路径 |
tag | 将渲染成某种标签 |
active-class | 设置链接激活时使用的 CSS 类名 |
exact-active-class | 配置当链接被精确匹配的时候应该激活的 class |
event | 声明可以用来除法导航的事件 |
router-view 是一个用于渲染页面的组件,实现指定路由对应组件的渲染,相当于一个占位的作用,配合 router-link 使用
配置示例
代码语言:javascript复制import Vue from 'vue';
import VueRouter from 'vue-router';
import A from '@/views/a.vue';
import B from '@/views/b.vue';
import C from '@/views/c.vue';
Vue.use(VueRouter);
const routes = [
{
path: '/',
name: 'home',
component: () => import('@/views/a') //可去后缀//其他:require('./views/index').default
},
{
path: '/a',
name: 'a',
component: A,
meta: { requireAuth: true }
},
{
path: '/b',
name: 'b',
component: B
},
{
path: '/c',
name: 'c',
component: C
},
{
path: '/login',
component: () => import('@/views/Login.vue'),
children: [
{
path: '',
name: 'register',
component: () => import('@/views/Register'),
meta: { requireGuest: true }
},
{
path: '/helper',
name: 'login.helper',
component: () => import('@/views/Helper')
}
],
meta: { requireGuest: true }
},
{
path: '*',
name: '404',
component: () => import('@/views/Error') //命名规范最好大写,驼峰。
}
];
const router = new VueRouter({
mode: 'hash', //history
routes
});
const VueRouterPush = VueRouter.prototype.push;
VueRouter.prototype.push = function push(to) {
return VueRouterPush.call(this, to).catch((err) => err);
};
router.beforeEach((to, from, next) => {
if (to.meta.requireAuth) {
//do something
return next({ name: 'login' });
}
if (from.meta.requireGuest) {
//do something
return next({ name: 'home' });
}
return next();
});
export default router;
使用模板
代码语言:javascript复制<template>
<div id="app">
<transition name="fade" mode="out-in">
<keep-alive>
<router-view />
</keep-alive>
</transition>
</div>
</template>
<script>
export default {
name: 'App',
methods: {}
};
</script>
<style>
html,
body {
width: 100%;
height: 100%;
}
#app {
width: 100%;
height: 100%;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.15s;
}
</style>
/* 此处过渡与动画效果参考后文 */
路由跳转
代码语言:javascript复制模板调用
// 不带参数
<router-link :to="{name: 'home'}">
<router-link :to="{path: '/home'}"> // name,path 都行,建议用 name。
// 注意:router-link 中链接如果是 '/' 开始就是从根路由开始,如果开始不带'/',则从当前路由开始。
// 带参数
<router-link :to="{name:'home', params: {id: 99}}">
// params 传参数 (类似 post)
// 路由配置 path: "/home/:id" 或者 path: "/home:id"
// 不配置 path,第一次可请求,刷新页面 id 会消失。
// 配置 path,刷新页面 id 会保留。
// html 取参 $route.params.id
// script 取参 this.$route.params.id
<router-link :to="{name:'home', query: {id: 99}}">
// query 传参数 (类似 get,url 后面会显示参数)
// 路由可不配置
// html 取参 $route.query.id
// script 取参 this.$route.query.id
代码语言:javascript复制函数调用
// 不带参数
this.$router.push('/home');
this.$router.push({name:'home'});
this.$router.push({path:'/home'});
// query传参
this.$router.push({name:'home',query: {id: 99}});
this.$router.push({path:'/home',query: {id: 99}});
// query 传参数 (类似 get,url 后面会显示参数)
// 路由可不配置
// html 取参 $route.query.id
// script 取参 this.$route.query.id
// params传参
this.$router.push({name:'home',params: {id: 99}}); // 只能用 name
// 路由配置 path: "/home/:id" 或者 path: "/home:id"
// 不配置 path,第一次可请求,刷新页面 id 会消失。
// 配置 path,刷新页面 id 会保留。
// html 取参 $route.params.id
// script 取参 this.$route.params.id
// query 和 params 区别
query 类似 get,跳转之后页面 url 后面会拼接参数,例如 ?id=1,非重要性数据的可以这样传,刷新后数据还在,密码之类还是用 params。
params 类似 post,跳转之后页面 url 后面不会拼接参数,但是刷新后数据消失。
// 其他方法,用法同上 push。
this.$router.replace();
this.$router.go(n); // -1 为退回上一页
// 区别
push:跳转到指定 url 路径,并向 history 栈中添加一个记录,点击后退会返回到上一个页面。
replace:跳转到指定 url 路径,但是 history 栈中不会有记录,点击返回会跳转到上上个页面(就是直接替换了当前页面)。
go:向前或者向后跳转 n 个页面,n 可为正整数或负整数。
过渡与动画
语法格式
代码语言:javascript复制<transition name="nameoftransition">
<div></div>
</transition>
// 定义进入前与离开后状态
.nameoftransition-enter, .nameoftransition-leave-to {
...
}
// 定义离开前与进入后状态
.nameoftransition-leave, .nameoftransition-enter-to {
...
}
// 定义进出过程
.nameoftransition-enter-active, .nameoftransition-leave-active {
...
}
切换类
Class | Description |
---|---|
v-enter | 定义进入过渡的开始状态 |
v-enter-active | 定义进入过渡生效时的状态 |
v-enter-to | 定义进入过渡的结束状态 |
v-leave | 定义离开过渡的开始状态 |
v-leave-active | 定义离开过渡生效时的状态 |
v-leave-to | 定义离开过渡的结束状态 |
自定义过渡的类名
- enter-class
- enter-active-class
- enter-to-class (2.1.8 )
- leave-class
- leave-active-class
- leave-to-class (2.1.8 )
同时使用过渡和动画
- 必须设置相应的时间监听器来知道过渡的完成
- 监听器可以是 transitionend 或 animationend
- 同时设置两种过渡效果时,需使用 type 特性设置 animation 或 transition 来明确声明需要监听的类型
全局状态管理(Vuex)
基础示例
代码语言:javascript复制import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const state = {
//相当于Vuex中的data,使用:
//this.store.state.test;
test: 'test'
};
const mutations = {
//相当于vuex中的数据处理methods,只能处理同步事件,异步操作使用actions配合进行。
//也可以同模组管理一样,统一使用mutations_type管理Mutations。[import * as types from '@/mutation-type';]
//使用即可type.MUTATIONS_TYPE。
//使用:
// this.store.commit('MUTATIONS_TYPE','hello world');
// this.store.commit({
// type: 'MUTATIONS_TYPE',
// payload: 'hello world'//推荐写成对象
// });
['MUTATIONS_TYPE'](state, payload) {
//也可以不写成常量,自己定义成普通方法。
state.test = payload;
}
};
const actions = {
//Action 提交的是 mutation,而不是直接变更状态。
//Action 可以包含任意异步操作。使用:
// this.store.dispatch('actionsName', {...});
// this.store.dispatch({
// type: 'actionsName',
// payload: {...}
// });
async actionsName(store, payload = {}) {
const { commit, dispatch, state, rootState, rootGetters } = store; //也可直接写到方法参数中解构赋值
console.log(rootGetters['others/get']); // 打印其他模块的 getters
try {
const {
data: { code, data }
} = await api.post('api/example', payload);
if (code === 200) {
commit('MUTATIONS_TYPE', data);
}
} catch (error) {
console.log(error);
}
}
};
const getters = {
//相当于vuex中的computed,使用:
//this.store.getters.testMore;
testMore(state, getters, rootState, rootGetters) {
//使用namespaced后,通过rootState可获取其他模块state等数据。
return state.test;
}
};
export default {
namespaced: true,
state,
mutations,
actions,
getters
};
模块化示例
代码语言:javascript复制//参考 [https://gitee.com/doubleam/biugle/tree/main/resources/js/store]
//modules更多使用请参考 [https://vuex.vuejs.org/zh/guide/modules.html]
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
//也可通过引入js文件的方式,独立此文件为index.js/建立同级文件夹modules管理模块/统一一个mutation_type管理Mutations
const moduleA = {
state: { ... },
mutations: { ... },
actions: { ... },
getters: { ... }
};
const moduleB = {
state: { ... },
mutations: { ... },
actions: { ... }
};
const store = new Vuex.Store({
namespaced: true,//访问与引入不同模块需加上命名空间 state.moduleA / [actions]('moduleA/xxx')
modules: {
moduleA: moduleA,
moduleB: moduleB
}
});
引入与使用
代码语言:javascript复制import { mapState, mapGetters, mapMutations, mapActions } from 'vuex';
export default {
computed: {
...mapState({
a: (state) => state.a,
b: (state) => state.b
}),
// 使用对象展开运算符将 getter 混入 computed 对象中
...mapGetters(['test1', 'test2'])
},
methods: {
...mapActions(['foo', 'bar']),
...mapMutations({
add: 'mutationsType' // 将 `this.add()` 映射为 `this.store.commit('mutationsType')`
})
}
};
其他
main 模板
代码语言:javascript复制import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store from './store.js'; // js 可省略
import './assets/css/reset.css';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import locale from 'element-ui/lib/locale/lang/zh-CN'; // lang i18n
import Axios from 'axios';
Vue.use(ElementUI, { locale });
Vue.prototype.axios = Axios;
Vue.config.productionTip = false;
Vue.config.debug = false;
Vue.config.devtools = false;
new Vue({
router,
store,
render: (h) => h(App)
}).mount('#main-container');
basic.vue 模板
代码语言:javascript复制<template>
<div>{{ msg }}</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {},
data() {
return {
msg: 'HelloBiugle'
};
},
components: {
xxx: xxx
},
computed: {
firstMsg: {
// getter
get: function () {
return 'first msg is' this.msg;
},
// setter
set: function (newValue) {
this.msg = newValue;
}
}
},
watch: {
msg(newMsg, oldMsg) {
this.msg = newMsg '=>' this.oldMsg;
}
},
created() {},
mounted() {},
updated() {},
destroyed() {},
methods: {}
};
</script>
<style scoped></style>
待补充
- 自定义指令
- 更多传值方式(前面提到未[举栗子])
- 混入
- 插槽
- 路由钩子与鉴权机制实现
- SSR
- Vue-cli
篇幅有限,这些需自己深入了解啦。