VueJS 基础知识

2023-12-11 20:33:42 浏览数 (1)

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">

代码语言:javascript复制
<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/setterObject.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。

  • 使用
代码语言:javascript复制
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

篇幅有限,这些需自己深入了解啦。

0 人点赞