Vue2 概述
Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的
渐进式框架;与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用;Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合;另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动;
1. Vue 最大的优势
Vue 作为一款轻量级框架、简单易学、数据绑定、组件化、数据和结构的分离、虚拟DOM、运行速度快,并且作者是中国人尤雨溪,对应的API文档对国内开发者优化,作为前端开发人员的首选入门框架, Vue有很多优势
- Vue.js 可以进行组件化开发,提升代码的复用性,使代码编写量大大减少,同项目的开发人员更加易于理解
- Vue.js 最突出的优势在于可以对数据进行双向绑定,并对数据作数据代理操作,方便开发人员操作
- 相比传统的页面通过超链接实现页面的切换和跳转, Vue使用路由技术使页面局部刷新,不用每次跳转页面都要请求所有数据和dom,这样大大加快了访问速度和提升用户体验
- 官方的 Vue-cli,Vue-Router,Vuex 等工具使用方便,极大的提升了开发效率
- 配合使用的第三方UI组件库使用方便,节省了很多开发时间
2. MVVM 模型
MVVM 是 Model-View-ViewModel 的缩写,它是一种基于前端开发的架构模式,其核心是提供对 View 和 ViewModel 的双向数据绑定,这使得 Model 的状态改变可以通过 ViewModel 自动传递给 View
在MVVM的架构下,View 层和 Model 层并没有直接联系,而是通过 ViewModel 层进行交互;ViewModel 层通过双向数据绑定将 View 层和 Model 层连接了起来,使得 View 层和 Model 层的同步工作完全是自动的;因此开发者只需关注业务逻辑,无需手动操作 DOM,复杂的数据状态维护交给 MVVM 统一来管理

3. MVVM 与 MVC 的区别
MVVM基本定义
MVVM 即Model-View-ViewModel的简写。即模型-视图-视图模型。模型(Model)指的是后端传递的数据。视图(View)指的是所看到的页面。视图模型(ViewModel)是mvvm模式的核心,它是连接view和model的桥梁。它有两个方向:一是将模型(Mode1)转化成视图(View),即将后端传递的数据转化成所看到的页面。实现的方式是:数据绑定。二是将视图(View)转化成模型(Model),即将所看到的页面转化成后端的数据。实现的方式是: DOM事件监听。这两个方向都实现的,我们称之为数据的双向绑定
MVC基本定义
MVC是Model-View- Controller的简写。即模型-视图-控制器。M和V指的意思和MVVM中的M和V意思一样。C即Controller指的是页面业务逻辑。使用MVC的目的就是将M和V的代码分离。MVC是单向通信。也就是View跟Model,必须通过Controller来承上启下。MVC和MVVM的区别并不是VM完全取代了C,只是在MVC的基础上增加了一层VM,只不过是弱化了C的概念,ViewModel存在目的在于抽离Controller中展示的业务逻辑,而不是替代Controller,其它视图操作业务等还是应该放在Controller中实现。也就是说MVVM实现的是业务逻辑组件的重用,使开发更高效,结构更清晰,增加代码的复用性
使用场景
MVC和MVVM其实区别并不大。都是一种设计思想。主要就是MVC中Controller演变成 MVVM中的viewModel, MVVM主要解决了MVC中大量的DOM操作使页面宣染性能降低,加载速度变慢,影响用户体验。
区别: Vue数据驱动,通过数据来显示视图层而不是节点操作
场景: 数据操作比较多的场景,需要大量操作DOM元素时,采用MVVM的开发方式,会更加便捷,让开发者更多的精力放在数据的变化上,解放繁琐的操作DOM元素。
Vue2 组成
1. vue-cli 脚手架项目目录
├─.browserslistrc -- 浏览器兼容文件
├─.editorconfig -- EditorConfig 规则配置
├─.eslintrc.js -- eslint 校验规则配置
├─.gitignore -- git 忽略配置
├─.prettierrc.js -- prettierrc 插件配置
├─babel.config.js -- babel 配置文件
├─jsconfig.json -- 项目配置文件
├─package-lock.json -- 包版本控制配置文件(名称、具体版本、下载地址 加快下载速度)
├─package.json -- 包配置文件(名称、版本)
├─README.md -- 项目说明
├─vue.config.js -- Vue 项目配置
├─src -- 源文件
| ├─App.vue -- 根组件
| ├─main.js -- 程序入口文件
| ├─views -- 路由组件目录
| ├─style
| | └index.scss -- scss 样式文件
| ├─store
| | └index.js -- vuex 配置文件
| ├─router
| | └index.js -- router 配置文件
| ├─pages -- 特有组件目录
| ├─components -- 公共组件目录
| ├─assets -- 静态资源文件目录(打包压缩)
| | └logo.png -- Logo
├─public -- 静态资源文件目录(打包不压缩)
| ├─favicon.ico -- 网页ICO文件
| └index.html -- 首页
├─node_modules -- 第三方插件目录
├─dist -- 打包输出目录
2. Vue2 组件构成
// 组件模板结构
<template>
<div class="app-container">
<!-- 路由占位符 -->
<router-view></router-view>
</div>
</template>
// 组件行为
<script>
export default {
// * 生命周期函数
beforeCreate() {} // 初始化: 声明周期,数据监听,数据代理 执行前
created() {} // 初始化: 声明周期,数据监听,数据代理 执行完毕
beforeMount() {} // 已在内存中生成虚拟 DOM,即将插入到真实 DOM 中
mounted() {} // 将内存中的虚拟 DOM 插入真实 DOM 完毕
beforeUpdate() {} // 监听到修改数据,更新页面结构前
updated() {} // 数据,页面更新完毕后
beforeDestroy() {} // 即将销毁组件之前
destroyed() {} // 销毁组件后
// * 配置项
// 挂载配置
el: '#app'
// 组件名称
name: 'App',
// 数据(函数式)
data() {
return {}
},
// 方法
methods: {},
// 计算属性
computed: {},
// 侦听器
watch: {},
// 过滤器
filters: {},
// 自定义指令
directives: {}
// 组件注册
components: {},
// 自定义属性
props: {}
}
</script>
// 组件样式
<style lang="scss" scoped> // lang=使用何种预处理器语言;scoped 防止样式冲突(为所有选择器添加组件特有属性)
// 样式穿透
/deep/ :deep ::v-deep
// 此处使用@ 需要在前方加上 ~ : ~@
</style>
3. vue-cli 脚手架工具
vue-cli 是 Vue.js 开发的标准工具;它简化了程序员基于 webpack 创建工程化的 Vue 项目的过程;引用自 vue-cli 官网上的一句话: 程序员可以专注在撰写应用上,而不必花好几天去纠结 webpack 配置的问题
**特点: **快速构建单页面应用程序(英文名: Single Page Application)简称 SPA,顾名思义,指的是一个 Web 网站中只有唯一的一个 HTML 页面,所有的功能与交互都在这唯一的一个页面内完成
npm i -g @vue/cli -- 安装
vue -V -- 查看版本
vue crrate projectname -- 创建项目
vue ui -- UI 方式创建项目
- UI 形式查看各类项目信息,生成打包报告
npm run serve -- 启动项目
npm run build -- 项目打包
--report // --report 选项可以生成 report.html 以帮助分析包内容
4. Vue 组件
组件化: 对某个功能所需代码和资源按照规则进行规范型的集合,以便复用
组件是可复用的 Vue 实例,且带有一个名字,组件解决的是 HTML CSS JS 相互引用,组织混乱以及复用性较差的问题
因为组件是可复用的 Vue 实例,所以它们与new Vue接收相同的选项,例如data、computed、watch、methods以及生命周期钩子等;仅有的例外是像el这样根实例特有的选项
通常一个应用会以一棵嵌套的组件树的形式来组织
VueComponent (构造函数)
组件本质是一个名为 VueComponent 的构造函数,且不是程序员定义的,是通过调用 Vue.extend()API 返回的,Vue.extend() 可以省略,可以直接传入一个配置对象,Vue 底层判断后自动调用Vue.extend()
且每一次使用 <组件></组件> , Vue 解析时会帮我们创建组件的实例对象
组件支持嵌套!!!
注意: 每次调用 Vue.extend() ,返回的都是一个全新的 VueComponent ! 注意: 一个组件的 data 选项必须是一个函数,组件中的 data 写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的 data,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。而单纯的写成对象形式,就使得所有组件实例共用了一份 data,造成一变则全变的结果this指向
- 组件配置中: data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【VueComponent实例对象】
- new Vue(options)配置中: data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【Vue实例对象】
重点: Vue 在创建实例对象时让实例对象的隐式原型属性(__proto__)指向了 Vue.prototype
// 一个重要的内置关系
// ? 组件实例对象(VueComponent)可以访问到 Vue原型上的属性、方法
VueComponent.prototype.__proto__ === Vue.prototype
Vue API
全局配置
Vue.config是一个对象,包含 Vue 的全局配置;可以在启动应用之前修改下列 property
Vue.config.silent = true // 取消 Vue 所有的日志与警告
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示
Vue.config.keyCodes.自定义键名 = 键码 // 定制按键别名
全局 API
Vue.extend( options ) // 使用基础 Vue 构造器,创建一个“子类”;参数是一个包含组件选项的对象,书写时可以省略,直接传入配置对象
Vue.set( target, propertyName/index, value ) // 向响应式对象中添加一个 property,并确保这个新 property 同样是响应式的,且触发视图更新;它必须用于向响应式对象上添加新 property,因为 Vue 无法探测普通的新增 property (比如 this.myObject.newProperty = 'hi')
- {Object | Function} plugin
- 注意: 对象不能是 Vue 实例,或者 Vue 实例的根数据对象
Vue.use( plugin ) // 安装 Vue.js 插件;如果插件是一个对象,必须提供 install 方法;如果插件是一个函数,它会被作为 install 方法;install 方法调用时,会将 Vue 作为参数传入
- 注意: 该方法需要在调用 new Vue() 之前被调用,当 install 方法被同一个插件多次调用,插件将只会被安装一次
Vue.directive('myDirective',{ // 注册或获取(接收)全局指令
// 指令与元素成功绑定时(一上来)
bind(element,binding) { ... }
// 指令所在元素被插入页面时
inserted(element,binding) { ... }
// 指令所在的模板被重新解析时
update(element,binding) { ... }
})
Vue.nextTick( [callback, context] ) // 在下次 DOM 更新循环结束之后执行延迟回调;在修改数据之后立即使用这个方法,获取更新后的 DOM
Vue.filter('myFilter',function(value){ // 注册或获取(接收)全局过滤器
return ... // 返回处理后的值
})
Vue.component( id, [definition] ) // 注册或获取全局组件;注册还会自动使用给定的 id 设置组件的名称
实例 property
vm.$data // Vue 实例观察的数据对象;Vue 实例代理了对其 data 对象 property 的访问
vm.$props // 当前组件接收到的 props 对象;Vue 实例代理了对其 props 对象 property 的访问
vm.$refs // 一个对象,持有注册过 ref attribute 的所有 DOM 元素和组件实例
实例方法/数据
// 全局侦听器;观察 Vue 实例上的一个表达式或者一个函数计算结果的变化;回调函数得到的参数为新值和旧值;表达式只接受简单的键路径;对于更复杂的表达式,用一个函数取代
vm.$watch( expOrFn, callback, [options] ) // 观察 Vue 实例上的一个表达式或者一个函数计算结果的变化;回调函数得到的参数为新值和旧值;表达式只接受简单的键路径;对于更复杂的表达式,用一个函数取代
- 注意: 在变更 (不是替换) 对象或数组时,旧值将与新值相同,因为它们的引用指向同一个对象/数组;Vue 不会保留变更之前值的副本
vm.$set( target, propertyName/index, value ) // 这是全局 Vue.set 的别名
vm.$delete( target, propertyName/index ) // 这是全局 Vue.delete 的别名
实例方法/事件
vm.$emit( eventName, […args] ) // 触发当前实例上的事件;附加参数都会传给监听器回调
vm.$on( event, callback ) // 监听当前实例上的自定义事件;事件可以由 vm.$emit 触发;回调函数会接收所有传入事件触发函数的额外参数
vm.$once( event, callback ) // 监听一个自定义事件,但是只触发一次;一旦触发之后,监听器就会被移除
vm.$off( [event, callback] ) // 移除自定义事件监听器
- 如果没有提供参数,则移除所有的事件监听器
- 如果只提供了事件,则移除该事件所有的监听器; 字符串<单个> || 数组<多个>
- 如果同时提供了事件与回调,则只移除这个回调的监听器
实例方法/生命周期
vm.$mount('#app') // 如果 Vue 实例在实例化时没有收到 el 选项,则它处于“未挂载”状态,没有关联的 DOM 元素;可以使用 vm.$mount() 手动地挂载一个未挂载的实例,返回vm - 实例自身
vm.$nextTick( [callback] ) // 将回调延迟到下次 DOM 更新循环之后执行;在修改数据之后立即使用它,然后等待 DOM 更新;它跟全局方法 Vue.nextTick 一样,不同的是回调的 this 自动绑定到调用它的实例上
vm.$destroy() // 完全销毁一个实例;清理它与其它实例的连接,解绑它的全部指令及事件监听器,触发 beforeDestroy 和 destroyed 的钩子;在大多数场景中你不应该调用这个方法;最好使用 v-if 和 v-for 指令以数据驱动的方式控制子组件的生命周期;
特殊 attribute
key // 主要用在 Vue 的虚拟 DOM 算法,在新旧 nodes 对比时辨识 VNodes,有相同父元素的子元素必须有独特的 key;重复的 key 会造成渲染错误
ref // 用来给元素或子组件注册引用信息,引用信息将会注册在父组件的 $refs 对象上,如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例
is // 用于动态组件且基于 DOM 内模板的限制来工作,使得组件标签可以写在特定标签中如<ul>
slot 废弃 // 用于标记往哪个具名插槽中插入子组件内容(推荐使用 v-slot )
scope 移除 // 用于表示一个作为带作用域的插槽的 <template> 元素,它在 2.5.0+ 中被 slot-scope 替代(推荐使用 v-slot )
slot-scope 废弃 // 用于将元素或组件表示为作用域插槽;attribute 的值应该是可以出现在函数签名的参数位置的合法的 JavaScript 表达式;这意味着在支持的环境中,你还可以在表达式中使用 ES2015 解构;它在 2.5.0+ 中替代了 scope(推荐使用 v-slot )
内置组件
component // 渲染一个“元组件”为动态组件;依 is 的值,来决定哪个组件被渲染
transition // 作为单个元素/组件的过渡效果;<transition> 只会把过渡效果应用到其包裹的内容上,而不会额外渲染 DOM 元素,也不会出现在可被检查的组件层级中
transition-group // 作为多个元素/组件的过渡效果;<transition-group> 渲染一个真实的 DOM 元素;默认渲染 <span>,可以通过 tag attribute 配置哪个元素应该被渲染,每个 <transition-group> 的子节点必须有独立的 key,动画才能正常工作
keep-alive // 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们;和 <transition> 相似,<keep-alive> 是一个抽象组件: 它自身不会渲染一个 DOM 元素,也不会出现在组件的父组件链中,当组件在 <keep-alive> 内被切换,它的 activated 和 deactivated 这两个生命周期钩子函数将会被对应执行;主要用于保留组件状态或避免重新渲染
slot // 作为组件模板之中的内容分发插槽;<slot> 元素自身将被替换
- name - string,用于命名插槽
Vue2 实例
1. Vue 实例概述
每个 Vue 应用都是通过用
Vue函数创建一个新的 Vue 实例开始的,并且在创建实例时需传入一个配置对象,配置对象中的 data 配置项中的属性, Vue 会对其进行数据代理,以实现响应式
注意: Vue 只会在实例创建时进行一次数据代理,后续添加的 data 属性不会代理el and data 的两种配置方式
// el 配置
el:'#app' // new Vue时候配置 el 属性
vm.$mount('#app') // 通过 Vue 方法指定 el 属性
// data 配置
data: ( ... ) // 对象式配置 data 数据项
data() { return { ... } } // 函数式配置 data 数据项 (组件/Vue3 强制使用)
2. Vue 模板
在 Vue "
#app"容器中的代码被称为Vue 模板,代码依然符合html规范,只不过混入了一些特殊的Vue语法
3. Vue 插值语法
用于解析标签体中的内容,内容只能填写 JS 表达式
<div>{{ 可以填写: JS 表达式; 访问 Vue 实例/原型上的属性 }}</div>
4. Vue 样式绑定
<div id="root">
// class 样式绑定
<!-- 绑定class样式--字符串写法,适用于: 样式的类名不确定,需要动态指定 -->
<div class="basic" :class="mood" @click="changeMood">{{name}}</div> <br/><br/>
<!-- 绑定class样式--数组写法,适用于: 要绑定的样式个数不确定、名字也不确定 -->
<div class="basic" :class="classArr">{{name}}</div> <br/><br/>
<!-- 绑定class样式--对象写法,适用于: 要绑定的样式个数确定、名字也确定,但要动态决定用不用 -->
<div class="basic" :class="classObj">{{name}}</div> <br/><br/>
// style 样式绑定
<!-- 绑定style样式--对象写法 -->
<div class="basic" :style="styleObj">{{name}}</div> <br/><br/>
<!-- 绑定style样式--数组写法 -->
<div class="basic" :style="styleArr">{{name}}</div>
</div>
Vue2 指令语法
用特定的指令语法来解析标签
v-bind (属性绑定)
v-bind:style="is ? true : false"; :style="is ? true : false"; :style="Vue实例=>data属性";
数据只能从 data 流向页面,支持表达式
v-bind可以简写为:,方便输入
v-model:value (双向数据绑定)
v-model:value="Vue实例=>data属性"; v-model="Vue实例=>data属性"
数据不仅能从 data 流向页面,还可以从页面流向 data;双向绑定一般都应用在表单类元素上(如: input、select等),不支持表达式
v-model:value可以简写为v-model,因为v-model默认收集的就是value值
数据修饰符
lazy -- 失去焦点再收集数据
number -- 输入字符串转为有效的数字(通常配置 input type="number" 使用)
trim -- 输入首尾空格过滤
收集表单数据
<input type="text"/> -- 则v-model收集的是value值,用户输入的就是value值
<input type="radio"/> -- 则v-model收集的是value值,且要给标签配置value值
<input type="checkbox"/>
- 没有配置input的value属性,那么收集的就是checked(勾选 or 未勾选,是布尔值)
- 配置input的value属性
- v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值)
- v-model的初始值是数组,那么收集的的就是value组成的数组
组件内更改默认 model 配置
model: {
prop: '*', // 修改默认 prop 名称
event: '*' // 修改默认 event.input 事件名称
}
v-on (事件绑定)
v-on:click="Vue实例=>methods方法"; v-on:click="showHi(target)"; v-on:click="showHi(target, $event)"; @click="showHi(target, $event)";
事件的回调需要配置在 methods 配置对象中,最终会在 vm 实例上,不支持表达式
v-on可以简写为@,方便输入
传参
在事件绑定时使用 () 就可以进行传参,默认传递事件对象,但显示指定传参会覆盖事件对象,$event可以显示指定传递事件对象事件修饰符
prevent -- 阻止默认事件(常用)
stop -- 阻止事件冒泡(常用)
once -- 事件只触发一次(常用)
capture -- 使用事件的捕获模式
self -- 只有 event.target 是当前操作的元素时才触发事件
passive -- 事件的默认行为立即执行,无需等待事件回调执行完毕
native -- 调用组件根元素原生事件操作
键盘事件
1. Vue 中常用的按键别名
回车 => enter
删除 => delete (捕获“删除”和“退格”键)
退出 => esc
空格 => space
换行 => tab (特殊,必须配合keydown去使用)
上 => up
下 => down
左 => left
右 => right
2. Vue未提供别名的按键,可以使用按键原始的key值去绑定,但注意要转为kebab-case(短横线命名)
3. 系统修饰键(用法特殊): ctrl、alt、shift、meta
- 配合keyup使用: 按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发
- 配合keydown使用: 正常触发事件
4. 也可以使用keyCode去指定具体的按键(不推荐)
与 sync 修饰符配置
<text-document
v-bind:title="doc.title"
v-on:update:title="doc.title = $event"
></text-document>
// 简写形式
<text-document v-bind:title.sync="doc.title"></text-document>
注意: 带有 .sync 修饰符的 v-bind 不能和表达式一起使用 (例如 v-bind:title.sync=”doc.title + ‘!’” 是无效的)。取而代之的是,你只能提供你想要绑定的 property 名,类似 v-model。
v-if/v-show (条件渲染)
v-if/v-else-if/v-else
v-if="is === true"; v-else-if="is === false"; v-else
使用于切换频率较低的场景,对不符合条件的 DOM 元素直接移除,如果后续再想获取 DOM 元素将报错
v-if 可以和 v-else-if、v-else 一起使用,但要求结构不能被“打断”
v-if 条件渲染与 v-for 列表渲染同时使用时,Vue2 先 for 后 if , Vue3 先 if 后 for(注意点),解决思路就是不一起使用
v-if 可以与 template 配合使用,在不破坏页面结构的情况下(不用添加用于布局的元素),显示/移除元素,template 在渲染时不显示
v-show
v-show="is ? true : false"
适用于一些切换频率较高的场景,对不符合条件的 DOM 元素使用 display: none 隐藏,DOM 元素可以获取
v-show 无法与 template 配合,原因可想而知,无法找到 v_v
v-for (列表渲染)
v-for="(item, index) in/of dataList" :key="item.id/index"
列表循环可遍历: 数组、对象、字符串(用的很少)、指定次数(用的很少)
key 是虚拟DOM对象的标识,当数据发生变化时,Vue会根据新数据生成新的虚拟DOM,随后Vue进行新虚拟DOM与旧虚拟DOM的差异比较,如果 Key 存在,判断内容是否变化,如有变化,重新渲染, Key 不存在,直接根据虚拟DOM重新渲染真实DOM
用index作为key可能会引发的问题: 1,若对数据进行: 逆序添加、逆序删除等破坏顺序操作,效率极低,需要全部重新渲染; 2,如果结构中还包含输入类的DOM,会产生错误DOM更新,界面渲染存在问题
开发中如何选择: 能够以 id 作为唯一的 Key 就选择 id,但如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,可以考虑使用 index 作为 Key
v-text (文本渲染)
<div v-text="str"></div>
向其所在的节点中渲染文本内容,与插值语法的区别: v-text 会替换掉节点中的内容,{{ … }} 则不会
v-html (HTML 渲染)
<div v-html="str"></div>
向指定节点中渲染包含html结构的内容, v-html 会替换掉节点中所有的内容,{{ … }} 则不会, v-html 可以识别
html结构
注意: 在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击; v-html 永要不要用在用户提交的内容上!!!
v-clock (控制显示)
[v-cloak]{
display:none;
}
<div v-cloak>{{name}}</div>
本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉 v-cloak 属性
使用 css 配合 v-cloak 可以解决网速慢时页面展示出 {{ xxx }} 的问题
v-once (渲染一次)
<div v-once>初始化的n值是:{{n}}</div>
v-once所在节点在初次动态渲染后,就视为静态内容了
数据的改变不会引起v-once所在结构的更新,可以用于优化性能
v-pre (跳过编译)
<div v-pre>跳过编译过程</div>
跳过其所在节点的编译过程
可利用它跳过: 没有使用指令语法、没有使用插值语法的节点,会加快编译
v-slot (插槽传递)
<template v-slot:header>
Header content
</template>
提供具名插槽: v-slot:name
或需要接收 prop 的插槽 v-slot=“data”
注意: 此指令限用于 <template> 和 组件(对于一个单独的带 prop 的默认插槽)
Vue2 配置选项
template (模板)
- 类型:
string- 详细: 一个字符串模板作为 Vue 实例的标识使用;模板将会替换挂载的元素;挂载元素的内容都将被忽略,除非模板的内容有分发插槽;如果值以
#开始,则它将被用作选择符,并使用匹配元素的 innerHTML 作为模板;常用的技巧是用<script type="x-template">包含模板;出于安全考虑,你应该只使用你信任的 Vue 模板;避免使用其他人生成的内容作为你的模板;如果 Vue 选项中包含渲染函数,该模板将被忽略;
template: `<div>模板内容</div>`
components (注册组件)
- 类型:
Object- 详细: 包含 Vue 实例可用组件的哈希表;
components: {
User:User
// 可简写
User
}
el (挂载配置)
- 类型:
string | Element- 限制: 只在用
new创建实例时生效;- 详细: 提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标;可以是 CSS 选择器,也可以是一个 HTMLElement 实例;在实例挂载之后,元素可以用
vm.$el访问如果在实例化时存在这个选项,实例将立即进入编译过程,否则,需要显式调用vm.$mount()手动开启编译;提供的元素只能作为挂载点;不同于 Vue 1.x,所有的挂载元素会被 Vue 生成的 DOM 替换;因此不推荐挂载 root 实例到<html>或者<body>上如果render函数和templateproperty 都不存在,挂载 DOM 元素的 HTML 会被提取出来用作模板,此时,必须使用 Runtime + Compiler 构建的 Vue 库;
el: '#app'
name (名称)
- 类型:
string- 限制: 只有作为组件选项时起作用;
- 详细: 允许组件模板递归地调用自身;注意,组件在全局用
Vue.component()注册时,全局 ID 自动作为组件的 name;指定name选项的另一个好处是便于调试;有名字的组件有更友好的警告信息;另外,当在有 vue-devtools,未命名组件将显示成<AnonymousComponent>,这很没有语义;通过提供name选项,可以获得更有语义信息的组件树;项目使用 keep-alive 时,可搭配组件 name 进行缓存过滤
name: 'App'
data (数据)
- 类型:
Object | Function- 限制: 组件的定义只接受
function;- 详细: Vue 实例的数据对象;Vue 会递归地把 data 的 property 转换为 getter/setter,从而让 data 的 property 能够响应数据变化;对象必须是纯粹的对象 (含有零个或多个的 key/value 对): 浏览器 API 创建的原生对象,原型上的 property 会被忽略;大概来说,data 应该只能是数据 - 不推荐观察拥有状态行为的对象;一旦观察过,你就无法在根数据对象上添加响应式 property;因此推荐在创建实例之前,就声明所有的根级响应式 property;实例创建之后,可以通过
vm.$data访问原始数据对象;Vue 实例也代理了 data 对象上所有的 property,因此访问vm.a等价于访问vm.$data.a;以_或$开头的 property 不会被 Vue 实例代理,因为它们可能和 Vue 内置的 property、API 方法冲突;你可以使用例如vm.$data._property的方式访问这些 property;当一个组件被定义,data必须声明为返回一个初始数据对象的函数,因为组件可能被用来创建多个实例;如果data仍然是一个纯粹的对象,则所有的实例将共享引用同一个数据对象!通过提供data函数,每次创建一个新实例后,我们能够调用data函数,从而返回初始数据的一个全新副本数据对象;如果需要,可以通过将vm.$data传入JSON.parse(JSON.stringify(...))得到深拷贝的原始数据对象;
data() {
return {
... // 数据会被代理到 vm 实例上
}
}
methods (方法)
- 类型:
{ [key: string]: Function }- 详细: methods 将被混入到 Vue 实例中;可以直接通过 VM 实例访问这些方法,或者在指令表达式中使用;方法中的
this自动绑定为 Vue 实例;注意,不应该使用箭头函数来定义 method 函数 (例如plus: () => this.a++);理由是箭头函数绑定了父级作用域的上下文,所以this将不会按照期望指向 Vue 实例,this.a将是 undefined;
methods: {
getData() { ... } // 不要用箭头函数! 箭头函数会让原本指向 vm 实例的 this 指向 window
}
computed (计算属性)
- 类型:
{ [key: string]: Function | { get: Function, set: Function } }- 详细: 计算属性将被混入到 Vue 实例中;所有 getter 和 setter 的 this 上下文自动地绑定为 Vue 实例;注意如果你为一个计算属性使用了箭头函数,则
this不会指向这个组件的实例,不过你仍然可以将其实例作为函数的第一个参数来访问;计算属性的结果会被缓存,除非依赖的响应式 property 变化才会重新计算;注意,如果某个依赖 (比如非响应式 property) 在该实例范畴之外,则计算属性是不会被更新的;& computed 无法进行异步操作什么时候触发计算:1. 页面第一次加载时; 2. 依赖的数据发生改变时
computed: { // 需要获取一个新属性,其获得依托于已有数据时,可以通过计算属性计算得出(最终返回结果会被代理到 vm 实例上,可以被直接访问)
fullName: {
// 当有人读取 fullName 时,get 就会被调用,且返回值就作为 fullName 的值
// 调用时机: 1. 初次读取 fullName 时; 2. 所依赖的数据发生变化时
get() {
// console.log(this) //此处的this是vm
},
// 修改 fullName 时, set 就会被调用,且 set 中要引起计算时依赖的数据发生改变,不返回值
set(value) { ... }
}
}
// 在只进行 get 操作时,可以简写
computed: {
...
return result
}
watch (侦听器)
- 类型:
{ [key: string]: string | Function | Object | Array }- 详细: 一个对象,键是需要观察的表达式,值是对应回调函数;值也可以是方法名,或者包含选项的对象;Vue 实例将会在实例化时调用
$watch(),遍历 watch 对象的每一个 property;& watch 侦听属性更改时触发,支持异步操作(计算属性能做的侦听器都能做,但侦听器能做的计算属性不一定能)& Vue 自身可以监测对象内部值的改变,但 Vue 提供的 watch 默认不可以(提升性能)!
watch: {
isHot: {
immediate: true, // 初始化时是否调用
deep: true, // 是否开启深度监视
//handler什么时候调用?当isHot发生改变时;
handler(newValue, oldValue) {
console.log('isHot被修改了', newValue,oldValue)
}
}
}
// 在不进行配置的情况下,可以简写
isHot(newValue, oldValue) {
console.log('isHot被修改了', newValue,oldValue,this)
}
filters (过滤器)
- 类型:
Object- 详细: 包含 Vue 实例可用过滤器的哈希表;
{{ date | timeFormater }}
// 过滤器
filters: { // 针对特有组件进行过滤,过滤器也可以接收额外参数、多个过滤器也可以串联,过滤完成返回新的值,不改变原有数据
timeFormater(value,str='YYYY年MM月DD日 HH:mm:ss') { // value:第一个参数总是需要需要过滤的值; str 不传递参数,默认赋值
return dayjs(value).format(str)
}
}
directive (自定义指令)
- 类型:
Object || Function- 详细: 包含 Vue 实例可用指令的哈希表& 指令定义时不加 v- ,但使用时要加 v-& 指令名如果是多个单词,要使用 kebab-case( - 分割) 命名方式,不要用 camelCase(小驼峰) 命名
fbind: {
// 指令与元素成功绑定时(一上来),配置相关属性
bind(element,binding){
element.value = binding.value
},
// 指令所在元素被插入页面时,只有 DOM 元素插入页面后才能操作
inserted(element,binding){
element.focus()
},
// 指令所在的模板被重新解析时,更新时配置相关属性
update(element,binding){
element.value = binding.value
}
}
// 不需要在插入页面之时操作数据时,可以简写,调用时机: 1.指令与元素成功绑定时(一上来); 2.指令所在的模板被重新解析时
big(element,binding) {
console.log('big', this) // 注意此处的this是window
element.innerText = binding.value * 10
}
props (自定义属性)
- 类型:
Array<string> | Object- 详细: props 可以是数组或对象,用于接收来自父组件的数据;props 可以是简单的数组,或者使用对象作为替代,对象允许配置高级选项,如类型检测、自定义验证和设置默认值;你可以基于对象的语法使用以下选项:
注意: props属性值不可以更改!!! (可以强制更改但不推荐) ,如果传递的值是对象,修改对象中属性不会报错,Vue只检测引用类型地址有没有更改
type: 可以是下列原生构造函数中的一种:String、Number、Boolean、Array、Object、Date、Function、Symbol、任何自定义构造函数、或上述内容组成的数组;会检查一个 prop 是否是给定的类型,否则抛出警告;Prop 类型的更多信息在此;default:any
为该 prop 指定一个默认值;如果该 prop 没有被传入,则换做用这个值;对象或数组的默认值必须从一个工厂函数返回;required:Boolean
定义该 prop 是否是必填项;在非生产环境中,如果这个值为 truthy 且该 prop 没有被传入的,则一个控制台警告将会被抛出;validator:Function
自定义验证函数会将该 prop 的值作为唯一的参数代入;在非生产环境下,如果该函数返回一个 falsy 的值 (也就是验证失败),一个控制台警告将会被抛出;你可以在这里查阅更多 prop 验证的相关信息;
// 简单语法
Vue.component('props-demo-simple', {
props: ['size', 'myMessage']
})
// 对象语法,提供验证
Vue.component('props-demo-advanced', {
props: {
// 检测类型
height: Number,
// 检测类型 + 其他验证
age: {
type: Number, // 类型检查
default: 0, // 默认值
required: true, // 必填项
validator: function (value) { // 自定义验证函数
return value >= 0
}
}
}
})
mixins (混入)
- 类型:
Array<Object>- 详细:
mixins选项接收一个混入对象的数组;这些混入对象可以像正常的实例对象一样包含实例选项,这些选项将会被合并到最终的选项中,使用的是和Vue.extend()一样的选项合并逻辑;也就是说,如果你的混入包含一个 created 钩子,而创建组件本身也有一个,那么两个函数都会被调用;Mixin 钩子按照传入顺序依次调用,并在调用组件自身的钩子之前被调用;(有组件混入则以组件混入为主)
var mixin = {
created: function () {
console.log('混入对象的钩子被调用')
}
}
new Vue({
mixins: [mixin],
created: function () {
console.log('组件钩子被调用')
}
})
// => "混入对象的钩子被调用"
// => "组件钩子被调用"
Vue2 生命周期
每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等;同时在这个过程中也会运行一些叫做
生命周期钩子的函数
Vue 的声明周期函数中的 this 自动关联到 Vue 实例上下文,所以在使用时不要使用箭头函数
重要的生命周期节点
- mounted: 发起 ajax 请求,开启定时器,绑定自定义事件,订阅消息等
初始化操作 - updated: 在更新数据和页面后需要进行操作时
- beforeDestroy: 清除定时器,解绑自定义事件,取消订阅信息等
收尾工作
组件特有
- activated: keep-alive组件激活时调用。该钩子在服务器端宣染期间不被调用
- deactivated: keep-alive 组件停用时调用。该钩子在服务器端宣染期间不被调用
新增
errorCaptured (2. 5. 0+ 新增): 当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传播
errorHandler: 为全局钩子,使用Vue. config. errorHandler 配置,接收参数与errorCaptured一致,2.6后可捕捉v-on与promise链的错误,可用于统一错误处理与错误兜底
Vue2 组件数据通信
原则: 数据在哪里,操作数据的方法就在哪里
1. props 实现
props 自定义属性主要用于
父 ==> 子传输数据; 也可以传递方法,子组件调用方法并传参从而使父组件取得子组件中的数据
// 父组件
<son :dataList="dataList" :getDataList="getData"></Son>
data(){
return {
dataList: [],
listData: {}
}
}
methods: {
getData(data){
this.listData = data
}
}
// 子组件
props: ['dataList','getDataList']
methods: {
setDataList(data){
this.getDataList(data)
}
}
2. 自定义事件实现
自定义事件主要用于
子 ==> 父传输数据
- 第一种实现: 父组件给子组件绑定事件( @eventName=“eventName” ),子组件触发事件( $emit(event,params) )
// 父组件
<Son @eventName="eventName"></Son>
...
methods: {
getData(data){
this.dataList = data
}
}
// 子组件
methods: {
setData(){
this.$emit('eventName',this.dataList)
}
}
- 第二种实现: 父组件给子组件绑定事件,获取组件示例,调用 o n 方法 , 将父组件的方法向子组件传递 , 实现 ( t h i s . on方法,将父组件的方法向子组件传递,实现( this. on方法,将父组件的方法向子组件传递,实现(this.refs.componentsName.$on(‘eventName’,this.fn) ),子组件触发事件( $emit(event,params) )
// 父组件
<Son ref="demo"/>
......
mounted(){
this.$refs.demo.$on('eventName',this.test)
}
// 子组件
methods: {
setData(){
this.$emit('eventName',this.dataList)
}
}
注意: $on() 方法绑定事件触发时,this指向默认是指向组件实例,如果想指向绑定事件(父)组件自身,一是绑定传递函数时使用 this.getData 方法,传递自身函数触发,二是使用 () => {} 使this向上寻找,指向组件自身
3. 全局事件总线 (GolbalEventBus)
一种组件间通信的实现方式,用于
任意组件传递数据
安装事件总线
new Vue({
......
beforeCreate() {
Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm
},
......
})
使用事件总线
- 接收数据
A组件想接收数据,则在A组件中给$bus绑定自定义事件,
事件的回调留在A组件自身
methods(){
demo(data){......}
}
......
mounted() {
this.$bus.$on('xxxx',this.demo)
}
- 提供数据
在B组件中触发全局事件总线中的事件并传递参数,实现组件之间的数据传递
this.$bus.$emit('xxxx',数据)
- 解绑事件
最好在 beforeDestroy 钩子中,用$off去解绑
当前组件所用到的事件
beforeDestroy: {
this.$bus.$off('xxxx')
}
4. 订阅与发布模式 (pubsub)
一种组件间通信的实现方式,用于
任意组件传递数据
安装 pubsub
npm install pubsub-js
使用 pubsub
- 接收数据
A组件想接收数据,则在A组件中订阅消息,
订阅的回调留在A组件自身
methods(){
demo(data){......}
}
......
mounted() {
this.pid = pubsub.subscribe('xxx',this.demo) // 订阅消息
}
- 提供数据
在B组件中发布事件并传递参数,实现组件之间的数据传递
pubsub.publish('xxx',数据)
- 解绑事件
最好在 beforeDestroy 钩子中,用
PubSub.unsubscribe(pid)去取消订阅
PubSub.unsubscribe(pid)
5. ref引用
$refs只会在组件渲染完成之后生效,并且它们不是响应式的。这仅作为一个用于直接操作子组件的“逃生舱”——你应该避免在模板或计算属性中访问$refs。
- 父组件在使用子组件的时候设置ref
<son ref="sonRef" />
- 父组件通过设置子组件ref来获取数据
this.$refs.sonRef // 获取子组件实例对象(以此来获取其身上的属性)
6. parent或root
$parent在绝大多数情况下,触达父级组件会使得你的应用更难调试和理解,尤其是当你变更了父级组件的数据的时候。当我们稍后回看那个组件的时候,很难找出那个变更是从哪里发起的。
$root对于 demo 或非常小型的有少量组件的应用来说这是很方便的。不过这个模式扩展到中大型应用来说就不然了。因此在绝大多数情况下,我们强烈推荐使用 Vuex 来管理应用的状态。
- 通过共同祖辈 parent(不推荐(后期维护麻烦))或者root(根组件实例<小型可以使用(推荐使用 vuex)>) 搭建通信侨联
- 兄弟组件
this.$parent.on ('add', this.add)
- 另一个兄弟组件
this.$parent.emit ('add')
7. attrs与listeners
$attrs包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (class和style除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class和style除外),并且可以通过v-bind="$attrs"传入内部组件——在创建高级别的组件时非常有用。
$listeners包含了父作用域中的 (不含.native修饰器的)v-on事件监听器。它可以通过v-on="$listeners"传入内部组件——在创建更高层次的组件时非常有用。
- 适用场景:祖先传递数据给子孙
- 设置批量向下传属性attrs和listeners
- 包含了父级作用域中不作为prop被识别(且获取)的特性绑定(class和style除外)。
- 可以通过v-bind="$attrs"传入内部组件
8. provide 与 inject
然而,依赖注入还是有负面影响的。它将你应用程序中的组件与它们当前的组织方式耦合起来,使重构变得更加困难。同时所提供的 property 是非响应式的。这是出于设计的考虑,因为使用它们来创建一个中心化规模化的数据跟使用
$root做这件事都是不够好的。如果你想要共享的这个 property 是你的应用特有的,而不是通用化的,或者如果你想在祖先组件中更新所提供的数据,那么这意味着你可能需要换用一个像 Vuex 这样真正的状态管理方案了。
- 在祖先组件定义provide属性,返回传递的值
- 在后代组件通过inject接收组件传递过来的值
// 祖先组件
provide() {
return {
foo:'foo'
}
}
// 后代组件
inject: ['foo']
9. Vuex
全局状态管理
Solt (插槽)
让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于
父组件 ==> 子组件
1. 默认插槽
父组件
<Son>
<div>html结构</div>
</Son>
子组件
<!-- 定义插槽 -->
<solt>插槽默认内容...<solt>
2. 具名插槽
父组件
<Son>
<template slot="center"> // 原有写法
<div>html结构1</div>
</template>
<template v-slot:footer> // 新API
<div>html结构2</div>
</template>
</Son>
子组件
<!-- 定义插槽 -->
<slot name="center">插槽默认内容...</slot>
<slot name="footer">插槽默认内容...</slot>
3. 作用域插槽
数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定;games数据在Category组件中,但使用数据所遍历出来的结构由App组件决定.作用域插槽其实就是带数据的插槽
父组件
<Category>
<template scope="scopeData">
<!-- 生成的是ul列表 -->
<ul>
<li v-for="g in scopeData.games" :key="g">{{g}}</li>
</ul>
</template>
</Category>
<Category>
<template slot-scope="scopeData">
<!-- 生成的是h4标题 -->
<h4 v-for="g in scopeData.games" :key="g">{{g}}</h4>
</template>
</Category>
子组件
<template>
<div>
<slot :games="games"></slot>
</div>
</template>
<script>
export default {
name: 'Category',
props: ['title'],
// 数据在子组件自身
data() {
return {
games: ['红色警戒', '穿越火线', '劲舞团', '超级玛丽']
}
}
}
</script>
3万+

被折叠的 条评论
为什么被折叠?



