Vue2学习笔记

本文详细介绍了Vue基础,包括Vue的官网、特点、与其他框架的关联,以及核心概念如模板语法、MVVM、计算属性、数据绑定、组件化、Ajax请求、UI库、路由和状态管理。深入浅出地讲解了Vue实例生命周期、过渡动画、过滤器、指令和自定义指令的使用。
摘要由CSDN通过智能技术生成

文章目录

第 1 章:Vue基础

1.1 Vue简介

1.1.1 官网

  1. 英文官网: https://vuejs.org/
  2. 中文官网: https://cn.vuejs.org/
  3. Vue3.0 + TypeScript: https://24kcs.github.io/vue3_study/

1.1.2 Vue的特点

  1. 遵循 MVVM 模式
  2. 编码简洁, 体积小, 运行效率高, 适合移动/PC 端开发
  3. 它本身只关注 UI, 可以轻松引入 vue 插件或其它第三库开发项目

1.1.3 与其它前端 JS 框架的关联

  1. 借鉴 angular模板数据绑定技术
  2. 借鉴 react组件化虚拟 DOM 技术

1.1.4 Vue 扩展插件

  1. vue-cli: vue 脚手架
  2. vue-resource(axios): ajax 请求
  3. vue-router: 路由
  4. vuex: 状态管理
  5. vue-lazyload: 图片懒加载
  6. vue-scroller: 页面滑动相关
  7. mint-ui: 基于 vue 的 UI 组件库(移动端)
  8. element-ui: 基于 vue 的 UI 组件库(PC 端)

1.2 Vue的基本使用

1.2.1 template模板

<template>
    <div id="app">
        <Main/>
    </div>
</template>

<script>
  import Header from '@/components/Layout/Header/Header';
  import Main from '@/components/Layout/Main/Main';
  import Navbar from '@/components/NavBar/NavBar';
  import { mapState, mapActions } from 'vuex';

  export default {
    name: 'App',
    components: {
      Main
    },
    data() {
      return {
        route: this.$route
      };
    },
    computed: {
      ...mapState({
        isH5Page: state => state.setting.isH5Page,
        activeNameText: state => state.setting.activeNameText
      })
    },
    created() {
    },
    mounted() {
      const screenWidth = document.body.clientWidth;
      screenWidth >= 800 ? this.setPageAction(false) : this.setPageAction(true);
    },
    methods: {
      ...mapActions(['setPageAction', 'setActiveNameText'])
    }
  };
</script>
<style lang="scss">
    #app {
        height: auto;
        min-width: 300px;
        background-color: #fff;
    }
</style>

1.2.2 理解 Vue 的 MVVM

在这里插入图片描述

1.3 模板语法

1.3.1 模板的理解

  1. 动态的 html 页面
  2. 包含了一些 JS 语法代码
    a. 双大括号表达式 {{}}
    b. 指令(以 v-开头的自定义标签属性)

1.3.2 双大括号表达式

  1. 语法: {{exp}}

  2. 功能: 向页面输出数据

  3. 可以调用对象的方法

    <span>{{ lang.mustChangePwd }}</span>
    

1.3.3 指令一: 强制数据绑定

  1. v-bind功能: 指定变化的属性值
  2. 简洁写法: :xxx='yyy'
    <el-tag
      v-for="(item, i) in data1" v-if="show > i"
      :class="{wrap:wrap}" :key="item"
      :style="{'font-size':fontSize || '13px'}"
      >
      {{getLabel(item)}}
    </el-tag>

1.3.4 指令二: 绑定事件监听

  1. v-on功能: 绑定指定事件名的回调函数
  2. 完整写法: v-on:keyup='xxx' v-on:keyup='xxx(参数)' v-on:keyup.enter='xxx'
  3. 简洁写法: @keyup='xxx' @keyup.enter='xxx'
<div @click="toLogin">
	<i class="iconfont iconcuowu"></i>
</div>

1.4 计算属性和监视

1.4.1 computed 计算属性

  • computed 属性对象中定义计算属性的方法

  • 在页面中使用{{方法名}}来显示计算的结果

     computed: {
            fullName: function () {
                return this.firstName + ' ' + this.lastName
            }
        }
    
  • 可以用来获取vuex里的状态

      computed: {
        ...mapState({
          userInfo: state => state.user.userInfo,
          isH5Page: state => state.setting.isH5Page
        }),
        ...mapGetters(["language"])
      },
    

计算属性高级

  1. 通过 getter/setter 实现对属性数据的显示和监视
  2. 计算属性存在缓存, 多次读取只执行一次 getter 计算

1.4.2. watch 监视属性

  • 通过 vm 对象的$watch()watch 配置来监视指定的属性
  • 当属性变化时, 回调函数自动调用, 在函数内部进行计算
  • watch只在被监听的属性值发生变化时执行.

1.使用immediate: true选项, 这样它就会在组件创建时立即执行.

  watch: {
    dog: {
      handler(newVal, oldVal) {
        console.log(`Dog changed: ${newVal}`);
      },
      immediate: true
    }
  }

2.使用deep: true选项, 开启深度监听

  watch: {
    obj: {
      handler(newVal, oldVal) {
        console.log(`obj changed: ${newVal}`);
      },
      immediate: true,
      deep: true
    }
  }

3.可只监听对象中的某一个key的变化

  watch: {
    'obj.hello': {
      handler(newVal, oldVal) {
        console.log(`obj changed: ${newVal}`);
      },
      immediate: true,
      deep: false
    }
  }

4.computedwatch 的差异

  1. computed 是计算一个新的属性,并将该属性挂载到 vm(Vue 实例)上,而 watch 是监听已经存在且已挂载到 vm 上的数据,所以用 watch 同样可以监听 computed 计算属性的变化(其它还有 data、props)
  2. computed 本质是一个惰性求值的观察者,具有缓存性,只有当依赖变化后,第一次访问 computed 属性,才会计算新的值,而 watch 则是当数据发生变化便会调用执行函数
  3. 从使用场景上说,computed 适用一个数据被多个数据影响,而 watch 适用一个数据影响多个数据;

1.5. class 与 style 绑定

使用v-on属性绑定实现

1.5.1 class 绑定

  1. :class='xxx'
  2. 表达式是字符串: 'classA'
  3. 表达式是对象: {classA:isA, classB: isB}
  4. 表达式是数组: ['classA', 'classB']

1.5.3 style 绑定

  1. :style="{ color: activeColor, fontSize: fontSize + 'px' }"
  2. 其中 activeColor/fontSizedata 属性

1.6 条件渲染

1.6.1 条件渲染指令

  1. v-ifv-else
  2. v-show

1.6.2 比较 v-if 与 v-show

  1. 如果需要频繁切换 v-show 较好
  2. 当条件不成立时, v-if 的所有子节点不会解析(项目中使用)

1.7. 列表渲染

  1. 列表显示指令
    数组: v-for / index
    对象: v-for / key
  2. 列表的更新显示
    删除 item
    替换 item
  3. 列表的高级处理
    列表过滤
    列表排序
<template v-for="(val,index) in data">
   <div :key="index" class="in-form" v-if="!val.hasOwnProperty('isShow') || val.isShow"></div>
</template>

1.8 事件处理

1.8.1 绑定监听:

  1. v-on:xxx="fun"
  2. @xxx="fun"
  3. @xxx="fun(参数)"
  4. 默认事件形参: event
  5. 隐含属性对象: $event

1.8.2 事件修饰符

  1. .prevent : 阻止事件的默认行为 event.preventDefault()
  2. .stop : 停止事件冒泡 event.stopPropagation()

1.8.3 按键修饰符

  1. .keycode : 操作的是某个 keycode 值的键
  2. .keyName : 操作的某个按键名的键(少部分)

1.9 表单输入绑定

1.9.1 使用 v-model 对表单数据自动收集

  1. text/textarea
  2. checkbox
  3. radio
  4. select

1.10 Vue 实例生命周期

1.10.1 生命周期流程图

在这里插入图片描述

1.10.2 vue 生命周期分析

  1. 初始化显示
    • beforeCreate()
    • created()
    • beforeMount()
    • mounted()
  2. 更新状态: this.xxx = value
    • beforeUpdate()
    • updated()
  3. 销毁 vue 实例: vm.$destory()
    • beforeDestory()
    • destoryed()

1.10.3 常用的生命周期方法

  1. created()/mounted(): 发送 ajax 请求, 启动定时器等异步任务
  2. beforeDestory(): 做收尾工作, 如: 清除定时器

1.11 过渡&动画

1.11.1 vue 动画的理解

  1. 操作 css 的 trasitionanimation
  2. vue 会给目标元素添加/移除特定的 class
  3. 过渡的相关类名
    xxx-enter-active: 指定显示的 transition
    xxx-leave-active: 指定隐藏的 transition
    xxx-enter/xxx-leave-to: 指定隐藏时的样式

在这里插入图片描述

1.11.2 基本过渡动画的编码

  1. 在目标元素外包裹<transition name="xxx">
  2. 定义 class 样式
    指定过渡样式: transition
    指定隐藏时的样式: opacity/其它

1.12 过滤器

1.12.1 理解过滤器

  1. 功能: 对要显示的数据进行特定格式化后再显示
  2. 注意: 并没有改变原本的数据, 可是产生新的对应的数据

1.12.2 定义和使用过滤器

  1. 定义过滤器
    Vue.filter(filterName, function(value[,arg1,arg2,...]){ 
    	// 进行一定的数据处理 
    	return newValue }) 
    
  2. 使用过滤器
    <div>{{myData | filterName}}</div> 
    <div>{{myData | filterName(arg)}}</div>
    

1.13 内置指令与自定义指令

1.13.1 常用内置指令

  1. v:text : 更新元素的 textContent
  2. v-html : 更新元素的 innerHTML
  3. v-if : 如果为 true, 当前标签才会输出到页面
  4. v-else: 如果为 false, 当前标签才会输出到页面
  5. v-show : 通过控制 display 样式来控制显示/隐藏
  6. v-for : 遍历数组/对象
  7. v-on : 绑定事件监听, 一般简写为@
  8. v-bind : 强制绑定解析表达式, 可以省略 v-bind
  9. v-model : 双向数据绑定
  10. ref : 指定唯一标识, vue 对象通过$refs 属性访问这个元素对象
  11. v-cloak : 防止闪现, 与 css 配合: [v-cloak] { display: none }

1.13.2 自定义指令

  1. 注册全局指令
    Vue.directive('my-directive', function(el, binding){ 
    	el.innerHTML = binding.value.toupperCase() 
    })
    
  2. 注册局部指令
    directives : { 
    	'my-directive' : { 
    		bind (el, binding) { 
    			el.innerHTML = binding.value.toupperCase() 
    		} 
    	} 
    }
    
  3. 使用指令
    v-my-directive='xxx'
    

第 2 章:vue 组件化编码

2.1. 使用 vue-cli 创建模板项目

2.1.1. 说明

  1. vue-cli 是 vue 官方提供的脚手架工具
  2. github: https://github.com/vuejs/vue-cli
  3. 作用: 从 https://github.com/vuejs-templates 下载模板项目

2.1.2. 创建 vue 项目

npm install -g 
vue-cli vue init webpack vue_demo 
cd vue_demo 
npm install 
npm run dev 
访问: http://localhost:8080/

2.1.3. 模板项目的结构

  • build : webpack 相关的配置文件夹(基本不需要修改)
    • dev-server.js : 通过 express 启动后台服务器
  • config: webpack 相关的配置文件夹(基本不需要修改)
    • index.js: 指定的后台服务的端口号和静态资源文件夹
  • node_modules 依赖包
  • src : 源码文件夹
    • components: vue 组件及其相关资源文件夹
    • App.vue: 应用根主组件
    • main.js: 应用入口 js
  • static: 静态资源文件夹
  • .babelrc: babel 的配置文件
  • .eslintignore: eslint 检查忽略的配置
  • .eslintrc.js: eslint 检查的配置
  • .gitignore: git 版本管制忽略的配置
  • index.html: 主页面文件
  • package.json: 应用包配置文件
  • README.md: 应用描述说明的 readme 文件

2.2. 项目的打包与发布

2.2.1. 打包:

npm run build

2.2.2. 发布 1: 使用静态服务器工具包

npm install -g serve 
serve dist 
访问: http://localhost:5000

2.2.3. 发布 2: 使用动态 web 服务器(tomcat)

修改配置: webpack.prod.conf.js

output: { publicPath: '/xxx/' //打包文件夹的名称 } 

重新打包:

 npm run build 

修改 dist 文件夹为项目名称: xxx
将 xxx 拷贝到运行的 tomcat 的 webapps 目录下
访问: http://localhost:8080/xxx

2.3. eslint

2.3.1. 说明

  1. ESLint 是一个代码规范检查工具
  2. 它定义了很多特定的规则, 一旦你的代码违背了某一规则, eslint会作出非常有用的提示
  3. 官网: http://eslint.org/
  4. 基本已替代以前的 JSLint

2.3.2. ESLint 提供以下支持

  1. ES
  2. JSX
  3. style 检查
  4. 自定义错误和提示

2.3.3. ESLint 提供以下几种校验

  1. 语法错误校验
  2. 不重要或丢失的标点符号,如分号
  3. 没法运行到的代码块(使用过 WebStorm 的童鞋应该了解)
  4. 未被使用的参数提醒
  5. 确保样式的统一规则,如 sass 或者 less
  6. 检查变量的命名

2.3.5. 相关配置文件

  1. .eslintrc.js : 全局规则配置文件
    'rules': { 'no-new': 1 }
    
  2. 在 js/vue 文件中修改局部规则
    /* eslint-disable no-new */ 
    new Vue({ el: 'body', components: { App } })
    
  3. .eslintignore: 指令检查忽略的文件
    *.js *.vue

2.4. 组件定义与使用

2.4.1. vue 文件的组成(3 个部分)

  1. 模板页面
    <template> 页面模板 </template>
    
  2. JS 模块对象
    <script> 
    export default { 
    	data() {return {}}, 
    	methods: {}, 
    	computed: {}, 
    	components: {} 
    } 
    </script>
    
  3. 样式
    <style>样式定义 </style>
    

2.4.2. 基本使用

  1. 引入组件

  2. 映射成标签

  3. 使用组件标签

    <template> 
    	<HelloWorld></HelloWorld> 
    	<hello-world></hello-world> 
    </template> 
    <script> 
    	import HelloWorld from './components/HelloWorld' 
    	export default { 
    		components: { 
    			HelloWorld 
    		} 
    	} 
    </script>
    

2.4.3. 关于标签名与标签属性名书写问题

  1. 写法一: 一模一样
  2. 写法二: 大写变小写, 并用-连接

2.5. 组件间通信

1.组件间通信基本原则

  1. 不要在子组件中直接修改父组件的状态数据
  2. 数据在哪, 更新数据的行为(函数)就应该定义在哪

2.vue 组件间通信方式

  1. props 2) $emit 3) 消息订阅与发布(如: pubsub 库) 4) slot 5) vuex(后面单独讲)

2.6 props

1.使用组件标签时

<my-component name='tom' :age='3' :set-name='setName'></my-component>

2.定义 MyComponent 时

  1. 在组件内声明所有的 props

  2. 方式一: 只指定名称

    props: ['name', 'age', 'setName']
    
  3. 方式二: 指定名称和类型

    props: { 
    	name: String, 
    	age: Number, 
    	setNmae: Function 
    }
    
  4. 方式三: 指定名称/类型/必要性/默认值

    props: { 
    	name: {type: String, required: true, default:xxx}, 
    	}
    

注意:

  1. 此方式用于父组件向子组件传递数据
  2. 所有标签属性都会成为组件对象的属性, 模板页面可以直接引用
  3. 问题:
    a. 如果需要向非子后代传递数据必须多层逐层传递
    b. 兄弟组件间也不能直接 props 通信, 必须借助父组件才可以

2.7 $emit

1.绑定事件监听

// 方式一: 通过 v-on 绑定 
@delete_todo="deleteTodo" 
// 方式二: 通过$on() 
this.$refs.xxx.$on('delete_todo', function (todo) {
	this.deleteTodo(todo) 
})

2.触发事件

// 触发事件(只能在父组件中接收) 
this.$emit(eventName, data)

注意:

  1. 此方式只用于子组件向父组件发送消息(数据)

  2. 问题: 隔代组件或兄弟组件间通信此种方式不合适

2.8 消息订阅与发布(PubSubJS 库)

此方式可实现任意关系组件间通信(数据)

1.订阅消息

PubSub.subscribe('msg', function(msg, data){})

2.发布消息

PubSub.publish('msg', data)

3. 事件的 2 个重要操作(总结)

  1. 绑定事件监听 (订阅消息)

    目标: 标签元素
    事件名(类型): click/focus
    回调函数: function(event){}

  2. 触发事件 (发布消息)
    DOM 事件: 用户在浏览器上对应的界面上做对应的操作
    自定义: 编码手动触发

2.9 slot

此方式用于父组件向子组件传递标签数据

1. 子组件: Child.vue

<template> 
	<div>
	<slot name="xxx">不确定的标签结构 1</slot> 
	<div>组件确定的标签结构</div> 
	<slot name="yyy">不确定的标签结构 2</slot> 
	</div> 
</template>

2. 父组件: Parent.vue

<child>
	<div slot="xxx">xxx 对应的标签结构</div> 
	<div slot="yyy">yyyy 对应的标签结构</div> 
</child>

第 3 章:vue-ajax

3.1. vue 项目中常用的 2 个 ajax 库

3.1.1. vue-resource

vue 插件, 非官方库, vue1.x 使用广泛

3.1.2. axios

通用的 ajax 请求库, 官方推荐, vue2.x 使用广泛

3.2. vue-resource 的使用

3.2.1. 在线文档

https://github.com/pagekit/vue-resource/blob/develop/docs/http.md

3.2.2. 下载

npm install vue-resource --save

3.2.3. 编码

// 引入模块 
import VueResource from 'vue-resource' 
// 使用插件 
Vue.use(VueResource)

// 通过 vue/组件对象发送 ajax 请求 this.$http.get('/someUrl').then((response) => { 
	// success callback 
	console.log(response.data) //返回结果数据 
}, (response) => { 
	// error callback
	console.log(response.statusText) //错误信息 
})

3.3. axios 的使用

3.3.2. 在线文档

https://github.com/pagekit/vue-resource/blob/develop/docs/http.md

3.3.3. 在线文档

npm install axios --save

3.3.4. 编码

// 引入模块 
import axios from 'axios' 

// 发送 ajax 请求 
axios.get(url) 
	.then(response => { 
		console.log(response.data) // 得到返回结果数据 
	})
		.catch(error => { 
			console.log(error.message) 
			})

第 4 章:vue UI 组件库

4.1. 常用

  1. Mint UI:
    a. 主页: http://mint-ui.github.io/#!/zh-cn
    b. 说明: 饿了么开源的基于 vue 的移动端 UI 组件库
  2. Elment
    a. 主页: http://element-cn.eleme.io/#/zh-CN
    b. 说明: 饿了么开源的基于 vue 的 PC 端 UI 组件库

4.2. 使用 Mint UI

4.2.1. 下载:

npm install --save mint-ui

4.2.2. 实现按需打包

1. 下载 
npm install --save-dev babel-plugin-component
2. 修改 babel 配置
"plugins": ["transform-runtime",["component", [ 
	{ 
		"libraryName": "mint-ui", 
		"style": true 
	} 
]]]

4.2.3. mint-ui 组件分类

  1. 标签组件
  2. 非标签组件

4.2.4. 使用 mint-ui 的组件

  1. main.js

    import {Button} from 'mint-ui' 
    Vue.component(Button.name, Button)
    
  2. App.vue

    <template> 
    	<mt-button @click="handleClick" type="primary" style="width: 100%">Test</mt-button> 
    </template> 
    
    <script> 
    	import {Toast} from 'mint-ui' 
    	export default { 
    		methods: { 
    			handleClick () { 
    				Toast('点击了测试'); 
    			} 
    		} 
    	} 
    </script>
    

第 5 章:vue-router

5.1. 理解

5.1.1. 说明

  1. 官方提供的用来实现 SPA 的 vue 插件
  2. github: https://github.com/vuejs/vue-router
  3. 中文文档: http://router.vuejs.org/zh-cn/
  4. 下载: npm install vue-router --save

5.1.2. 相关 API 说明

  1. VueRouter(): 用于创建路由器的构建函数

    new VueRouter({ // 多个配置项 })
    
  2. 路由配置

    routes: [ 
    	{ // 一般路由 
    		path: '/about', 
    		component: About 
    	},
    	{ // 自动跳转路由 
    		path: '/', 
    		redirect: '/about' 
    	} 
    ]
    
  3. 注册路由器

    import router from './router' 
    new Vue({ router })
    
  4. 使用路由组件标签

    1. <router-link>: 用来生成路由链接 
    	<router-link to="/xxx">Go to XXX</router-link> 
    2. <router-view>: 用来显示当前路由组件界面 
    	<router-view></router-view>
    

5.2. 基本路由

5.2.2. 路由组件

Home.vue
About.vue

5.2.3. 应用组件: App.vue

<div> 
	<!--路由链接--> 
	<router-link to="/about">About</router-link> 
	<router-link to="/home">Home</router-link> 
	<!--用于渲染当前路由组件--> 
	<router-view></router-view> 
</div>

5.2.4. 路由器模块: src/router/index.js

export default new VueRouter({ 
	routes: [ 
		{ 
			path: '/', 
			redirect: '/about' 
		},
		{ 
			path: '/about', 
			component: About 
		},
		{ 
			path: '/home', 
			component: Home 
		} 
	] 
})

5.2.5. 注册路由器: main.js

import Vue from 'vue' 
import router from './router' 
// 创建 vue 配置路由器 
new Vue({ 
	el: '#app', 
	router, 
	render: h => h(app) 
})

5.2.6. 优化路由器配置

linkActiveClass: ‘active’, // 指定选中的路由链接的 class

5.2.7. 总结: 编写使用路由的 3 步

  1. 定义路由组件
  2. 注册路由
  3. 使用路由
    <router-link>
    <router-view>

5.3. 嵌套路由

5.3.2. 子路由组件

News.vue
Message.vue

5.3.3. 配置嵌套路由: router.js

path: '/home', 
component: home, 
children: [ 
	{ 
		path: 'news', 
		component: News 
	},
	{ 
		path: 'message', 
		component: Message 
	} 
]

5.3.4. 路由链接: Home.vue

<router-link to="/home/news">News</router-link> 
<router-link to="/home/message">Message</router-link> 
<router-view></route-view>

5.4. 向路由组件传递数据

5.4.2. 方式 1: 路由路径携带参数(param/query)

  1. 配置路由

    children: [ 
    	{ 
    		path: 'mdetail/:id', 
    		component: MessageDetail 
    	} 
    ]
    
  2. 路由路径

    <router-link :to="'/home/message/mdetail/'+m.id">{{m.title}}</router-link>
    
  3. 路由组件中读取请求参数

    this.$route.params.id
    

5.4.3. 方式 2: 属性携带数据

<router-view :msg="msg"></router-view>

5.5. 缓存路由组件对象

5.5.1. 理解

  1. 默认情况下, 被切换的路由组件对象会死亡释放, 再次回来时是重新创建的
  2. 如果可以缓存路由组件对象, 可以提高用户体验

5.5.2. 编码实现

<keep-alive> 
	<router-view></router-view> 
</keep-alive>

5.6.2. 相关 API

  1. this.$router.push(path): 相当于点击路由链接(可以返回到当前路由界面)
  2. this.$router.replace(path): 用新路由替换当前路由(不可以返回到当前路由界面)
  3. this.$router.back(): 请求(返回)上一个记录路由
  4. this. r o u t e r . g o ( − 1 ) : 请求 ( 返回 ) 上一个记录路由 5 ) t h i s . router.go(-1): 请求(返回)上一个记录路由 5) this. router.go(1):请求(返回)上一个记录路由5)this.router.go(1): 请求下一个记录路由

第 6 章:vuex

6.1. vuex 理解

6.1.1. vuex 是什么

  1. github 站点: https://github.com/vuejs/vuex
  2. 在线文档: https://vuex.vuejs.org/zh-cn/
  3. 简单来说: 对 vue 应用中多个组件的共享状态进行集中式的管理(读/写)

6.1.2. 状态自管理应用

  1. state: 驱动应用的数据源
  2. view: 以声明方式将 state 映射到视图
  3. actions: 响应在 view 上的用户输入导致的状态变化(包含 n 个更新状态的方法)

在这里插入图片描述

6.1.3. 多组件共享状态的问题

  1. 多个视图依赖于同一状态
  2. 来自不同视图的行为需要变更同一状态
  3. 以前的解决办法
    a. 将数据以及操作数据的行为都定义在父组件
    b. 将数据以及操作数据的行为传递给需要的各个子组件(有可能需要多级传递)
  4. vuex 就是用来解决这个问题的

6.2. vuex 核心概念和 API

6.2.1. state

  1. vuex 管理的状态对象

  2. 它应该是唯一的

    const state = { xxx: initValue }
    

6.2.2. mutations

  1. 包含多个直接更新 state 的方法(回调函数)的对象
  2. 谁来触发: action 中的 commit(‘mutation 名称’)
  3. 只能包含同步的代码, 不能写异步代码
const mutations = { 
	yyy (state, {data1}) { 
		// 更新 state 的某个属性 
	} 
}

6.2.3. actions

  1. 包含多个事件回调函数的对象
  2. 通过执行: commit()来触发 mutation 的调用, 间接更新state
  3. 谁来触发: 组件中:$store.dispatch('action 名称', data1) // 'zzz'
  4. 可以包含异步代码(定时器, ajax)
const actions = { 
	zzz ({commit, state}, data1) { 
		commit('yyy', {data1}) 
	} 
}

6.2.4. getters

  1. 包含多个计算属性(get)的对象
  2. 谁来读取: 组件中: $store.getters.xxx
const getters = { 
	mmm (state) { 
		return ...
	} 
}

6.2.5. modules

  1. 包含多个 module
  2. 一个 module 是一个 store 的配置对象
  3. 与一个组件(包含有共享数据)对应

6.2.6. 向外暴露 store 对象

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

6.2.7. 组件中

import {mapState, mapGetters, mapActions} from 'vuex' 

export default { 
	computed: { 
		...mapState(['xxx']), 
		...mapGetters(['mmm']), }
		methods: mapActions(['zzz']) }

{{xxx}} {{mmm}} @click="zzz(data)"

6.2.8. 映射 store

import store from './store' 
new Vue({ store })

6.2.9. store 对象

  1. 所有用 vuex 管理的组件中都多了一个属性$store, 它就是一个 store 对象
  2. 属性:
    state: 注册的 state 对象
    getters: 注册的 getters 对象
  3. 方法:
    dispatch(actionName, data): 分发调用 action

6.5. vuex 结构分析

在这里插入图片描述

第 7 章:vue 源码分析

7.1. 说明

  1. 分析 vue 作为一个 MVVM 框架的基本实现原理
    • 数据代理
    • 模板解析
    • 数据绑定
  2. 剖析 github 上某基友仿 vue 实现的 mvvm 库
  3. 地址: https://github.com/DMQ/mvvm

7.2. 准备知识

  1. [].slice.call(lis): 将伪数组转换为真数组
  2. node.nodeType: 得到节点类型
  3. Object.defineProperty(obj, propName, {}): 给对象添加/修改属性(指定描述符)
    configurable: true/false 是否可以重新 define
    enumerable: true/false 是否可以枚举(for…in / keys())
    value: 指定初始值
    writable: true/false value 是否可以修改
    get: 回调函数, 用来得到当前属性值
    set: 回调函数, 用来监视当前属性值的变化
  4. Object.keys(obj): 得到对象自身可枚举的属性名的数组
  5. DocumentFragment: 文档碎片(高效批量更新多个节点)
  6. obj.hasOwnProperty(prop): 判断 prop 是否是 obj 自身的属性

7.3. 数据代理

  1. 数据代理: 通过一个对象代理对另一个对象(在前一个对象内部)中属性的操作(读/写)
  2. vue 数据代理: 通过 vm 对象来代理 data 对象中所有属性的操作
  3. 好处: 更方便的操作 data 中的数据
  4. 基本实现流程
    a. 通过 Object.defineProperty()vm 添加与 data 对象的属性对应的属性描述符
    b. 所有添加的属性都包含 getter/setter
    c. getter/setter 内部去操作 data 中对应的属性数据

7.4. 模板解析

7.4.1. 模板解析的基本流程

  1. el 的所有子节点取出, 添加到一个新建的文档 fragment 对象中
  2. fragment 中的所有层次子节点递归进行编译解析处理
    • 对大括号表达式文本节点进行解析
    • 对元素节点的指令属性进行解析
      • 事件指令解析
      • 一般指令解析
  3. 将解析后的 fragment 添加到 el 中显示

7.4.2. 模板解析(1): 大括号表达式解析

  1. 根据正则对象得到匹配出的表达式字符串: 子匹配/RegExp.$1 name
  2. data 中取出表达式对应的属性值
  3. 将属性值设置为文本节点的 textContent

7.4.3. 模板解析(2): 事件指令解析

  1. 从指令名中取出事件名
  2. 根据指令的值(表达式)从 methods 中得到对应的事件处理函数对象
  3. 给当前元素节点绑定指定事件名和回调函数的 dom 事件监听
  4. 指令解析完后, 移除此指令属性

7.4.4. 模板解析(3): 一般指令解析

  1. 得到指令名和指令值(表达式) text/html/class msg/myClass
  2. data 中根据表达式得到对应的值
  3. 根据指令名确定需要操作元素节点的什么属性
    • v-texttextContent 属性
    • v-htmlinnerHTML 属性
    • v-classclassName 属性
  4. 将得到的表达式的值设置到对应的属性上
  5. 移除元素的指令属性

7.5. 数据绑定

7.5.1. 数据绑定

一旦更新了 data 中的某个属性数据, 所有界面上直接使用或间接使用了此属性的节点都会 更新

7.5.2. 数据劫持

  1. 数据劫持是 vue 中用来实现数据绑定的一种技术
  2. 基本思想: 通过 defineProperty()来监视 data 中所有属性(任意层次)数据的变化, 一旦变化就去更新界面

7.5.3. 四个重要对象

7.5.3.1 Observer

a. 用来对 data 所有属性数据进行劫持的构造函数
b. 给 data 中所有属性重新定义属性描述(get/set)
c. 为 data 中的每个属性创建对应的 dep 对象

7.5.3.2 Dep(Depend)

a. data 中的每个属性(所有层次)都对应一个 dep 对象
b. 创建的时机:

  • 在初始化 define data 中各个属性时创建对应的 dep 对象
  • data 中的某个属性值被设置为新的对象时

c. 对象的结构

{ 
	id, // 每个 dep 都有一个唯一的 id 
	subs //包含 n 个对应 watcher 的数组(subscribes 的简写) 
}

d. subs 属性说明

  • watcher 被创建时, 内部将当前 watcher 对象添加到对应的 dep 对象的 subs
  • 当此 data 属性的值发生改变时, subs 中所有的 watcher 都会收到更新的通知,从而最终更新对应的界面
7.5.3.3 Compiler

a. 用来解析模板页面的对象的构造函数(一个实例)
b. 利用 compile 对象解析模板页面
c. 每解析一个表达式(非事件指令)都会创建一个对应的 watcher 对象, 并建立 watcherdep 的关系
d. compliewatcher 关系: 一对多的关系

7.5.3.4 Watcher

a. 模板中每个非事件指令或表达式都对应一个 watcher 对象
b. 监视当前表达式数据的变化
c. 创建的时机: 在初始化编译模板时
d. 对象的组成

{ 
	vm, //vm 对象 
	exp, //对应指令的表达式 
	cb, //当表达式所对应的数据发生改变的回调函数 
	value, //表达式当前的值 
	depIds //表达式中各级属性所对应的 dep 对象的集合对象 //属性名为 dep 的 id, 属性值为 dep 
}
7.5.3.5 总结: dep 与 watcher 的关系: 多对多

a. data 中的一个属性对应一个 dep, 一个 dep 中可能包含多个 watcher(模板中有几个表达式使用到了同一个属性)
b. 模板中一个非事件表达式对应一个 watcher, 一个 watcher 中可能包含多个 dep(表达式是多层: a.b)
c. 数据绑定使用到 2 个核心技术

  • defineProperty()
  • 消息订阅与发布

7.6. MVVM 原理图分析

在这里插入图片描述

7.7. 双向数据绑定

  1. 双向数据绑定是建立在单向数据绑定(model==>View)的基础之上的
  2. 双向数据绑定的实现流程:
    a. 在解析 v-model 指令时, 给当前元素添加 input 监听
    b. 当 input 的 value 发生改变时, 将最新的值赋值给当前表达式所对应的 data 属性
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值