【前端】Vue2.x 快速入门

Vue2.x 快速入门

快速且全量的Vue2.x入门参考,快来看看吧!

前言

最近发现身边的大佬都非常卷,个个都是全栈。作为后端渣渣,势必要走出舒适区,向大佬们学习全栈了。其中重要的一环便是前端技术栈。对于前端还没入门的我,决定从Vue2.x开始学习。

这篇博客是我看B站吴悠老师的视频做的笔记,吴悠老师讲得非常好,既有效率,又非常全面,视频链接在文末,非常感谢吴悠老师!

前提

  • 了解过 HTML 、 CSS、 JavaScript 基础三件套
  • 了解 Node.js, 会用 npm 、yarn 等工具对前端项目进行管理

学习目标

  • 快速学习 Vue2.x 特性
  • 快速学习 Vue2.x 相关语法,接下来能逐渐熟练使用并逐步拥有全栈的能力
  • 学习Vue2.x 为后续 Vue3.x、 React 等框架打下基础

1. Vue 项目创建

1.1 Script 标签引入

标签引入Vue,就可以直接使用了:

CDN方式

	<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>

vue.js
我们也可以直接从官网上下载 vue.js 或 vue.min.js

官网vue.js下载页面

	<!-- 引入Vue.js -->
    <script src="../public/vue.min.js"></script>

1.2 Vue-Cli 创建项目

首先保证自己本地/服务器有node。推荐使用nvm去管理我们的node。

安装 Vue 脚手架

  • 卸载已有的脚手架
npm uninstall vue-cli -g

出现以下类似结果即为成功

up to date in 80ms
  • 安装脚手架
npm install -g @vue/cli
  • 查看vue cli 版本
vue -V

# 或者使用
vue --version
  • 创建项目
    在目标文件夹,cmd 键入:
vue create [projectname]

例如,当前项目名是:

vue create kcl2024_background_front_end

之后会进入如下选择界面。

选择版本

Vue CLI v5.0.8
? Please pick a preset: (Use arrow keys)
> Default ([Vue 3] babel, eslint)
  Default ([Vue 2] babel, eslint)
  Manually select features

选择我们需要的版本,默认3、2或自定义。
接下来执行,根据提示选择,然后等待执行即可。

  • 尝试启动
    本地启动vue cli 创建的项目有如下几种方式,读者按需选用:

进入项目文件夹:

npm run serve

打包并启动:

npm run build

npm i serve -g

serve dist

ui方式:

vue ui

2. Vue2.x 语法

以下,跟着参考教程的步伐,我们快速了解一下 Vue2.x 的语法吧

2.1 插值表达式与响应式数据

响应式数据
响应式数据是一种机制,是指在数据发生变化后,更新依赖这些数据的部分,允许数据绑定和试图更新的自动化,为我们编写代码时省略DOM操作,提升开发效率。

插值表达式
使用此处示例的语法结构,就可用插值表达式将响应式数据渲染,如{{ data_name }}

举例
下面列举一个例子,使用插值表达式就能将title和content响应式数据渲染:

<div id="app">
        <!-- 插值表达式 -->
        <h1>{{ title }}</h1>
        <p>{{ content }}</p>
</div>
<script>
        // 创建Vue实例
        const vm = new Vue({
            // 1. 响应式数据与插值表达式
            // el : vue 实例的一个配置属性,指定了 Vue 实例要渲染的位置,可以是 CSS 选择器、HTML 元素或者是 HTMLElement 实例。
            el: '#app',
            data () {
                return {
                    title: '这是标题',
                    content: '这是内容'
                }
            },
        })
</script>

其中,插值表达式里也可以调用运算、方法等,例如:

<div id="app">
        <!-- 插值表达式 -->
        <h1>{{ title }}</h1>
        <p>{{ content }}</p>
        <!-- 自定义方法 -->
        <p>{{ description() }}</p>
</div>
<script>
        // 创建Vue实例
        const vm = new Vue({
            el: '#app',
            data () {
                return {
                    title: '这是标题',
                    content: '这是内容'
                }
            },
            // 方法,和data属性并列
            methods: {
                // 自定义方法
                description () {
                    return '标题:' + this.title + ',内容:' + this.content
                }
            },
        })
</script>

2.2 计算属性

<!-- 引入Vue.js -->
<script src="../public/vue.min.js"></script>
<div id="app">
        <!-- 对比计算属性与普通方法 -->
        <p>{{ computedTest }}</p>
        <p>{{ computedTest }}</p>
        <p>{{ computedTest }}</p>
        <p>{{ computedCompare() }}</p>
        <p>{{ computedCompare() }}</p>
        <p>{{ computedCompare() }}</p>
</div>
<script>
        // 创建Vue实例
        const vm = new Vue({
            el: '#app',
            data () {
                return {
                    title: '这是标题',
                    content: '这是内容'
                }
            },
            // 方法,和data属性并列
            methods: {
                computedCompare () {
                    console.log('methods方法被访问了')
                    return '这是methods方法的输出'
                }
            },
            // 2. 计算属性,可以缓存一些复杂的逻辑,避免每次调用都重复计算
            computed: {
                // 计算属性的 getter 函数返回一个值,这个值会根据它的依赖跟踪依赖的响应式数据,并自动更新
                // 计算属性的 setter 函数会在计算属性的依赖发生变化时调用,并传入新值作为参数
                computedTest () {
                    console.log('计算属性被访问了')
                    return '这是计算属性的输出'
                }
            }
        })
</script>

说明
计算属性只会在计算属性里面的响应式数据变动了之后再重新计算,如果数据没变就直接使用缓存的上次计算结果,提升了性能。因此在上述例子里我们可以从我们举例的log中去发现该例子的计算属性调用次数确实比methods调用次数要少。

另外,计算属性是属性,因此在调用的时候不需要像方法一样调用,而是使用属性的方式调用即可。

2.3 侦听器

侦听器是 Vue 给我们开放的一个功能,其目的是在我们对响应式数据进行操作的时候,可以做一些其它操作,方便我们对程序进行拓展。

举例

<div id="app">
        <!-- 插值表达式 -->
        <h1>{{ title }}</h1>
</div>
<script>
	const vm = new Vue({
            // 1. 响应式数据与插值表达式
            // el : vue 实例的一个配置属性,指定了 Vue 实例要渲染的位置,可以是 CSS 选择器、HTML 元素或者是 HTMLElement 实例。
            el: '#app',
            data () {
                return {
                    title: '这是标题',
                    content: '这是内容'
                }
            },
            watch: {
                // 监听器,可以监听数据的变化,并自动执行一些操作
                title (newVal, oldVal) {
                    console.log('监听器被访问了')
                    console.log('标题被修改了,新值:' + newVal + ',旧值:' + oldVal)
                }
            }
</script>

我们可以在f12控制台对上述例子的title进行修改,然后观察输出的值。

2.4 指令

这一小节介绍常见的Vue指令,也就是我们常见的v-for等。

内容指令
内容指令会覆盖掉标签里的内容。

<div id="app">
        <!-- 指令 -->
        <p v-text="title">此内容会被覆盖</p>
        <p v-text="htmlContent">此内容会被覆盖</p>
        <p v-html="htmlContent">此内容会被覆盖</p>
</div>
<script>
        // 创建Vue实例
        const vm = new Vue({
            // 1. 响应式数据与插值表达式
            // el : vue 实例的一个配置属性,指定了 Vue 实例要渲染的位置,可以是 CSS 选择器、HTML 元素或者是 HTMLElement 实例。
            el: '#app',
            data () {
                return {
                    title: '这是标题',
                    content: '这是内容',
                    htmlContent: '这是一个span标签:<span>这是内容,此标签会被v-html指令渲染</span>'
                }
            }
        })
</script>

渲染指令

  • v-for 循环:
    举例:
<!--    渲染指令    -->
<p v-for="item in arr">循环arr:{{item}}}</p>
<p v-for="(value, key) in obj">循环obj:{{key}}:{{value}}</p>
<p v-for="(value, key, index) in obj">循环arr:{{key}} : {{value}} : {{index}}</p>

data () {
          return {
                  arr: ['one', 'two', 'three'],
                  obj: {
                          name: '张三',
                          age: 20,
                          job: '前端工程师'
                    }
                 }
           },
  • v-if 与 v-show:
    举例:
<p v-if="bool">v-if指令渲染</p>
<p v-if="!bool">v-if指令不会渲染</p>
<p v-show="bool">v-show指令渲染</p>
<p v-show="!bool">v-show指令不会渲染</p>
    
data(){
	bool: true
}

注意,v-if 会决定元素是否销毁。一般在不需要销毁元素的场景,我们多数使用 v-show 来决定元素的显示。

属性指令

  • 属性绑定
    举例:
<!--    属性指令    -->
<p v-bind:title="title">v-bind指令绑定title属性</p>
<p :title="title">简写v-bind指令绑定title属性</p>

v-bind 还可以绑定 class、style等,例如:

<!--    属性指令 class    -->
<p v-bind:class="{ active: isActive }">v-bind指令绑定class属性</p>
<p :class="{ active: isActive }">简写v-bind指令绑定class属性</p>
<!--    样式指令    -->
<p v-bind:style="{ color: activeColor }">v-bind指令绑定style属性</p>
<p :style="{ color: activeColor }">简写v-bind指令绑定style属性</p>

事件指令
举例:

<!--    事件指令    -->
<button v-on:click="computedCompare">按钮触发事件</button>
<button @click="computedCompare">按钮触发事件</button>

表单指令
表单指令主要用于实现双向数据绑定。
举例:

<!--    表单指令:v-model, 双向数据绑定    -->
<input type="text" v-model="inoutValue">
<p>{{ inoutValue }}</p>

data () {
         return {
             inoutValue:'输入内容'
         }
},

修饰符
我们可以采用一些修饰符,来对我们的数据做一些处理。
举例:

<input type="text" v-model="inputValue">
<p>{{ inputValue }}</p>
<input type="text" v-model.trim="inputValue">

这个例子列举的trim是将两端空格去掉,读者可以参考着试一试。

3. Vue组件化开发

3.1 Vue Cli 项目结构

首先打开我们用Vue Cli创建的项目:
01

以下列举我们需要重点关注的项目结构:

  • dist: build后的文件,服务器里运行的是dist
  • node_modules: 所需依赖文件,npm install 的文件
  • public:保存一些不需要参与编译的资源
  • src:
    • assets: 参与编译的一些静态资源
    • components:自定义组件
    • router:路由
    • store: vuex 相关

3.2 Vue 文件结构

一般来说一个 Vue 的一个结构有三部分: template、script 和 style
例如HelloWorld.vue:

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <p>
      For a guide and recipes on how to configure / customize this project,<br>
      check out the
      <a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
    </p>
    <h3>Installed CLI Plugins</h3>
    <ul>
      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-router" target="_blank" rel="noopener">router</a></li>
      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-vuex" target="_blank" rel="noopener">vuex</a></li>
    </ul>
    <h3>Essential Links</h3>
    <ul>
      <li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
      <li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
      <li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
      <li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
      <li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
    </ul>
    <h3>Ecosystem</h3>
    <ul>
      <li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
      <li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
      <li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
      <li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
      <li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
    </ul>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
  margin: 40px 0 0;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>

3.3 组件通信

组件化开发指的是一个vue页面可以由多个、存在父子关系的组件组成。这一小节介绍父子通信。

3.3.1 父组件传给子组件

例如,我们刚创建出来的Vue默认页面中,HelloWorld.vueHomeView.vue的子组件。

子组件中,通过<script>标签内的 props参数接收由父组件传递的参数,其中,props值的key是传递值的名字,value是接收类型,例如:

HomeView.vue

<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png">
    <HelloWorld
        msg="Welcome to Your Vue.js App"
        count="5"
    />
  </div>
</template>

HelloWorld.vue

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <h1>Count: {{ count }}</h1>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  // 接收父组件传递的 msg、count 属性
  props: {
    msg: String,
    count: Number
  }
}
</script>

其中,props也可以一个key定义接收多个类型的值,同时,可以有默认值,举个例子:

HomeView.vue

<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png">
    <HelloWorld
        msg="Welcome to Your Vue.js App"
        count="5"
        more="This is more text"
    />
  </div>
</template>

HelloWorld.vue

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <h1>Count: {{ count }}</h1>
    <h3>More: {{ more }}</h3>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  // 接收父组件传递的 msg、count 属性
  props: {
    msg: String,
    count: Number,
    more: {
      // 类型
      type: [Object, Array, String, Number],
      // 是否必填, 决定这个属性是否必须传递给组件
      required: true,
      // 默认值
      default: 100
    }
  }
}
</script>

执行效果
02

3.3.2 子组件传给父组件

使用自定义事件的方式将值传递给父组件,以下举例:

我们先在子组件定义一个数据,并给一个触发事件的按钮:
HelloWorld.vue

<template>
  <div class="hello">
    <button @click="increment">按钮</button>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  // 接收父组件传递的 msg、count 属性
  props: {
    childData: Number
  },
  data() {
    return {
      childDataCount:0
    }
  },
  methods: {
    increment() {
      this.childDataCount++
      // 触发父组件的 increment 事件,自定义事件
      this.$emit('increment', this.childDataCount)
    }
  }
}
</script>

接着,我们在父组件之间调用子组件的自定义事件,用于接收:

<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png">
    <h1>父组件中接收到的数据: {{ childData }}</h1>
    <HelloWorld
        :childData="childData"
        @increment="handleClick"
    />
  </div>
</template>

<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'

export default {
  name: 'HomeView',
  components: {
    HelloWorld
  },
  data() {
    return {
      childData: 10
    }
  },
  methods: {
    // 子组件向父组件传递的数据
    handleClick(dataFromChild) {
      this.childData = dataFromChild
    }
  }
}
</script>

3.4 插槽

使用插槽可以让我们实现一些相同组件的一些不同显示,而不在组件中传参实现。

3.4.1 默认插槽

我们想让我们自定义的内容在组件标签内显示:

HomeView.vue

<template>
  <div class="home">
    <SoltDemo> 内容1 </SoltDemo>
    <SoltDemo> 内容2 </SoltDemo>
    <SoltDemo> </SoltDemo>
  </div>
</template>

SoltDemo.vue

<template>
  <div>
    <slot> Default slot content </slot>
  </div>
</template>

示例执行结果
03

3.4.2 具名插槽

我们在定义插槽时可以指定name,然后通过#号或者v-slot让组件使用:

SoltDemo.vue

<template>
  <div>
    <slot> Default slot content </slot>
    <slot name="header"> Header slot content </slot>
  </div>
</template>

HomeView.vue

<template>
  <div class="home">
    <SoltDemo>
      <template #header>
        header插槽内容1
      </template>
    </SoltDemo>
    <SoltDemo>
      内容2
      <template v-slot:header>
        header插槽内容2
      </template>
    </SoltDemo>
    <SoltDemo>  </SoltDemo>
  </div>
</template>

3.4.3 作用域插槽

我们可以给插槽绑定一个数据作为作用域插槽,调用方式我们直接如下举例:

SlotDemo.vue

<script>
export default {
  name: 'SlotDemo',
  data() {
    return {
      slotData :0
    }
  }
}
</script>

<template>
  <div>
    <slot> Default slot content </slot>
    <slot name="header"> Header slot content </slot>
    <slot name="footer" :slotData="slotData"> Footer slot content </slot>
  </div>
</template>

HomeView.vue

<template>
  <div class="home">
    <SoltDemo>
      <template #header>
        header插槽内容1
      </template>
    </SoltDemo>
    <SoltDemo>
      内容2
      <template v-slot:header>
        header插槽内容2
      </template>
      <template v-slot:footer = "slotDataObj">
        {{slotDataObj}}
      </template>
    </SoltDemo>
    <SoltDemo>  </SoltDemo>
    <SoltDemo>
      <template #header>
        header插槽内容3
      </template>
      <template #footer = "slotData">
        {{slotData.slotData}}
      </template>
    </SoltDemo>
    <SoltDemo>
      <template #header>
        header插槽内容4
      </template>
      <template #footer ={slotData}>
        {{slotData}}
      </template>
    </SoltDemo>
  </div>
</template>

值得注意的是,作用域插槽使用方式有多种,参考上述例子。其中,直接在template中 = "xxx"的方式获取的是一个对象。

4. 路由

路由用于Vue单页面跳转,是我们日后开发要常接触的部分。

4.1 基本结构与使用方式

基本结构
我们用脚手架进行项目生成时,可以选择手动选择功能,然后选择路由。当我们选择了路由后,生成的Vue项目中就会有一个router文件夹。这个文件夹下会有一个index.js文件:

import Vue from 'vue'
import VueRouter from 'vue-router'
import HomeView from '../views/HomeView.vue'

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'home',
    component: HomeView
  },
  {
    path: '/about',
    name: 'about',
    // 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/AboutView.vue')
  }
]

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

export default router

基本使用方式
路由index.js文件定义了基本的路由使用方式,即在routes中加入如:

{
    path: '/',
    name: 'home',
    component: HomeView
}

这样的组件信息配置。其中,component可以直接写组件名,同时要import相应的这个组件;或者直接使用箭头函数import这个组件。

练习
了解了基本用法后,我们可以模仿一个出来:

LearnView.vue:

<template>
  <h1>This is a component for learning</h1>
</template>

<script>
export default {
  name: 'LearnView'
}
</script>

index.js:

import LearnView from '../views/LearnView.vue'

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'home',
    component: HomeView
  },
  {
    path: '/about',
    name: 'about',
    // 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/AboutView.vue')
  },
  {
    path: '/learn',
    name: 'learn',
    component: LearnView
  }
]

_App.vue_新增如下:

<router-link to="/learn">for learning</router-link>

效果:
04

4.2 动态路由

我们实际的项目,url后可能会拼接一个id等字符来显示特定某个对象的信息,例如商品详情等。这种url拼接动态参数的方式称为动态路由。

实现动态路由要以下步骤:

冒号拼接参数名
index.js:

{
    path: '/item/:id',
    name: 'item',
    component: () => import('../views/ItemView.vue'),
    props:true
}

同时要注意,要加一行props=true来接收动态参数。

props传参
itemView.vue:

<script>
export default {
  name: 'ItemView',
  props: [
    'id'
  ]
}
</script>

<template>
  <div class="item-view">
    <h1>Item View</h1>
    <p>item id: {{ id }}</p>
  </div>
</template>

params传参或路径传参
App.vue:

<router-link :to="{ name: 'item', params: { id: 123 } }"> item </router-link>

效果:
05

同时我们观察url,参数已经拼在url末尾。

4.3 嵌套路由

嵌套路由的步骤如下:

设置children子组件列表
index.js:

{
    path: '/children/:id',
    name: 'children',
    children: [
      {
        path: 'child1',
        name: 'child1',
        component: () => import('../views/Child1View.vue')
      },
      {
        path: 'child2',
        name: 'child2',
        component: () => import( '../views/Child2View.vue')
      }
    ],
    component: () => import(/* webpackChunkName: "children" */ '../views/ChildrenView.vue'),
    props: true
}

嵌套链接
ChildrenView.vue

<template>
  <div>
    <h1>Children View</h1>
    <router-link to="/child1">儿子1</router-link>
    <br>
    <router-link to="/child2">儿子2</router-link>
    <router-view/>
  </div>
</template>

被嵌套的组件及接下来的调用过程略,效果:
06

4.3 编程式路由

编程式路由允许由我们编码指定跳转。例如,当业务状态发生变更时,跳转道指定页面。

如:
Child1View

export default {
  name: 'Child1View',
  created () {
    setTimeout(() => {
      this.$router.push({ name: 'home' })
    }, 3000)
  }
}

其中,这个例子created函数是一个生命周期函数,具体会在下文生命周期小节有介绍。

4.4 路由守卫

在Vue2中,可以使用全局的路由守卫来监控和响应路由的导航。

我们简单举个例子,在路由_index.js_下添加如下:

// 全局前置守卫
router.beforeEach((to, from, next) => {
  console.log('router.beforeEach', to, from)
  next()
})

这个路由守卫输出了页面跳转的路径。但不要忘了next()

这里只介绍了基本用法。一般来说,路由守卫可以做一些逻辑处理,如身份验证、权限校验、加载数据等。

5. VueX

VueX 状态管理,是一种统一是数据存储方式,是解决多层级组件传值的一种有效手段。

我们在使用脚手架创建Vue项目时就可以选择引入VueX。项目创建后,src目录下会有一个store文件夹,这个文件夹下也有一个_index.js_文件。

其基本结构如下:

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

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
  },
  getters: {
  },
  mutations: {
  },
  actions: {
  },
  modules: {
  }
})

我们需要注意的是,从 state 到 modules 提供了5个功能,下面逐一介绍。

5.1 state 数据存储

state 可以理解为在一个地方存数据,然后所有组件都可访问。

举例
index.js:

 state () {
    return {
      status: 'loading'
    }
 }

访问方式:
Cild1View.vue:

export default {
  name: 'Child1View',
  created () {
    console.log(this.$store.state.status)
  }
}

5.2 mutations 数据修改

如果我们的VueX全局变量需要修改,则可在mutations进行。

举例
index.js:

state () {
    return {
      testMutation: 0
    }
  },
mutations: {
    testChangeValue (state, value) {
      // 返回 + 1 的值
      state.testMutation = value + 1
    }
}

调用方式:
Cild1View.vue:

export default {
  name: 'Child1View',
  created () {
    this.handler()
    console.log(this.$store.state.status)
  },
  methods: {
    handler () {
      console.log(this.$store.commit('testChangeValue', 1))
    }
  }
}

控制台输出,即可查看结果。

同时,在上面介绍的Demo练习例子中,我们不难发现,VueX中的数据都是在state中拿的,使用过程中需要遵循使用方式,即“state.xxx”这种方式去调用。

5.3 actions 异步处理

VueX中actions的作用是提供异步处理。
和mutations类似,都是方法处理,只不过是异步。因此以下复用了部分上一小节举的例子。

举例
index.js:

actions: {
    testAction (store, payload) {
      store.commit('testChangeValue', payload)
    }
  }

调用方式也和mutations类似,注意是使用store的dispatch调用:

console.log(this.$store.dispatch('testAction', 2))

5.4 getters 缓存

getters 提供了 类似于计算属性的缓存。只要getters中的值没有变化,就只执行一次,提高程序效率。

举例
index.js:

testGetters (state) {
      console.log('testGetters executed', state.status)
      return state.status.length
}

测试示例:
Cild1View.vue:

export default {
  name: 'Child1View',
  methods: {
    handler () {
      console.log(this.$store.getters.testGetters)
      console.log(this.$store.getters.testGetters)
      console.log(this.$store.getters.testGetters)
      console.log(this.$store.getters.testGetters)
    }
  }
}

这里示例调用了好几次,但是在控制台输出不难发现console.log('testGetters executed', state.status)只调用了一次。

5.5 modules 模块

在 Vuex 中,模块(modules)是一种将 store 分割成更小的、更专注的部分的方式。每个模块可以包含自己的 state、mutations、actions、getters,甚至是嵌套子模块。这种结构使得 Vuex store 可以保持清晰和组织良好,特别是在大型应用中。

举例
index.js:

 modules: {
    myModule: {
      state: {
        myModuleStatus: 'inactive',
        myModuleCounter: 0
      },
      getters: {
        myModuleStatusLength: (state) => {
          console.log('myModuleStatusLength executed', state.myModuleStatus);
          return state.myModuleStatus.length;
        }
      },
      mutations: {
        incrementCounter (state) {
          state.myModuleCounter++;
          console.log('myModuleCounter', state.myModuleCounter);
        }
      },
      actions: {
        incrementAction ({ commit }) {
          commit('incrementCounter');
        }
      },
      modules: {
        // 可以继续嵌套子模块,在开发中一般会单独建一个文件,用来管理多个模块之间的数据状态
      }
    }

使用示例:

this.$store.commit('myModule/incrementCounter')
      this.$store.dispatch('myModule/incrementAction')

6. Vue2 生命周期

概念
Vue 2 的生命周期钩子是指在 Vue 实例从创建到销毁的过程中,Vue 提供的一系列特殊的函数,这些函数在实例生命周期的不同阶段被自动调用。以下是 Vue 2 生命周期钩子的列表及其说明:

  • beforeCreate:在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。此时,组件实例的 data 和 methods 已经被定义,但是 data 的响应式属性尚未被设置,$el 属性也还未创建。

  • created:在实例创建完成后被立即调用。此时,实例已完成数据观测,属性和方法的运算,watch/event 事件回调。但是,挂载阶段还没开始,$el 属性目前还不可见。

  • beforeMount:在挂载开始之前被调用:相关的 render 函数首次被调用。此时,$el 还未被渲染,data 仍然是响应式的。

  • mounted:在实例被挂载后调用,此时可以访问到 e l 属性,表示 D O M 已经被渲染。如果根实例挂载到了文档内, el 属性,表示 DOM 已经被渲染。如果根实例挂载到了文档内, el属性,表示DOM已经被渲染。如果根实例挂载到了文档内,el 也在文档内可访问。

  • beforeUpdate:在数据变化时,DOM 重新渲染之前调用,此时可以在这个钩子中进一步地更改状态,这不会触发重绘。

  • updated:在由于数据更改导致的虚拟 DOM 重新渲染和打补丁之后调用。此时可以执行依赖于 DOM 的操作。

  • beforeDestroy:在实例销毁之前调用。在这一步,实例仍然完全可用。

  • destroyed:在实例销毁之后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。

  • activated 和 deactivated:这两个钩子只在 keep-alive 组件中使用。activated 在组件被激活时调用,deactivated 在组件被停用时调用。

  • errorCaptured:当捕获一个来自子孙组件的错误时被调用。它有三个参数:错误对象、发生错误的组件实例和错误来源。

这些生命周期钩子可以被用来执行一些特定的操作,比如数据获取、事件监听、清理工作等。每个钩子函数都可以在组件选项中被定义,并且会在相应的生命周期阶段被调用。

简单举例
例如,我们可以将生命周期函数在我们项目的main.js中各做一个简单的输出:
main.js

new Vue({
  router,
  store,
  render: h => h(App),
  beforeCreate () {
    console.log('beforeCreate: Vue 实例被创建,但数据观测和事件/侦听器还未被设置')
  },
  created () {
    console.log('created: Vue 实例已创建,data() 和 methods 已可用')
  },
  beforeMount () {
    console.log('beforeMount: Vue 实例即将被挂载,$el 属性还不可用')
  },
  mounted () {
    console.log('mounted: Vue 实例已经挂载到DOM,$el 属性已可用')
  },
  beforeUpdate () {
    console.log('beforeUpdate: Vue 实例数据更新,DOM 重新渲染之前')
  },
  updated () {
    console.log('updated: Vue 实例数据更新,DOM 重新渲染完成')
  },
  beforeDestroy () {
    console.log('beforeDestroy: Vue 实例销毁之前')
  },
  destroyed () {
    console.log('destroyed: Vue 实例销毁完成')
  }
}).$mount('#app')

7. 总结

我们从基本使用的层面,从Vue2.x 项目创建开始,结合一些Demo,学习了 Vue2.x的基本语法,然后学习了组件化开发中的父子组件传值。之后,我们接着学习日常开发中需要常接触的路由配置,以及可以解决多层级组件传值麻烦的全局状态管理器VueX,最后再介绍了面试常见与日后进一步了解框架所需的Vue2.x生命周期函数。

掌握基本语法是基础,组件化开发的思路是重要思想,路由、VueX也是实际开发中常接触的东西。

本文的示例都只是些Demo,要进一步了解、学习前端,还得找些项目练习、实战。

Vue2.x 是学习前端框架开发的一个良好台阶,可以为后续 Vue3.x、React等框架打下一定的基础。持续学习,共同进步!

参考教程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值