Vue详细介绍及使用 |
您所在的位置:网站首页 › 椭圆的定义及有关概念是什么意思 › Vue详细介绍及使用 |
Vue详细介绍及使用
一、Vue定义及简介
1、Vue定义
关于Vue简介,百度百科给出的解释是:Vue.js是一套构建用户界面的渐进式框架。与其他重量级框架不同的是,Vue 采用自底向上增量开发的设计。Vue 的核心库只关注视图层,并且非常容易学习,非常容易与其它库或已有项目整合。另一方面,Vue 完全有能力驱动采用单文件组件和Vue生态系统支持的库开发的复杂单页应用。 Vue.js 是一个提供了 MVVM 风格双向数据绑定的 Javascript 库(无依赖别的js库,直接引入一个js文件就可以使用,跟jquery差不多),专注于View 层。它的核心是 MVVM 中的 VM,也就是 ViewModel。 ViewModel负责连接 View 和 Model,保证视图和数据的一致性,这种轻量级的架构让前端开发更加高效、便捷。 2、Vue背景简介 2.1、Vue诞生的背景从历史的潮流来说,人们从之前的:原生JS -> Jquery之类的类库 -> 前端模板引擎 ,他们都有一个共同的特点需要我们去操作dom元素。近几年来,得益于手机设备的普及和性能的提升,移动端的web需求大量增加,产生了一种叫webapp的东西,也就是移动端的网页应用。为了更好满足当前移动webapp项目的开发需求,MVVM框架诞生,而Vue便是这样的一种框架。那么什么是Vue? 官网有一句对它的介绍:通过尽可能简单的API实现响应的数据绑定和组合的视图组件。Vue的核心主要包括下面两块: Vue的数据驱动:数据改变驱动了视图的自动更新,传统的做法你得手动改变DOM来改变视图,vuejs只需要改变数据,就会自动改变视图; 视图组件化:把整一个网页的拆分成一个个区块,每个区块我们可以看作成一个组件。网页由多个组件拼接或者嵌套组成(可维护、可重用)。 2.2、MVVM框架的发展MVC(View Model Controller )模式: MVC框架最早出现在Java领域,在经典的MVC模式中,是用户通过Controller来操作Model以达到View的变化。MVC 即 Model-View-Controller 的缩写,就是 模型—视图—控制器,也就是说一个标准的Web 应用程式是由这三部分组成的: View :用来把数据以某种方式呈现给用户; Model :其实就是数据; Controller :接收并处理来自用户的请求,并将 Model 返回给用户; MVP(Model View Presenter)模式: 而后的MVP模式(MVC模式的演变)逻辑层在Presenter里实现,而且Presenter与具体的View 是没有直接关联的,而是通过定好的接口进行交互(在MVC中View会直接从Model中读取数据而不是通过 Controller)。 View 与 Model 不发生联系,都通过 Presenter 传递。 在HTML5 还未火起来的那些年,MVC 作为Web 应用的最佳实践是很OK 的,这是因为 Web 应用的View 层相对来说比较简单,前端所需要的数据在后端基本上都可以处理好,View 层主要是做一下展示,那时候提倡的是 Controller 来处理复杂的业务逻辑,所以View 层相对来说比较轻量,就是所谓的瘦客户端思想。 相对 HTML4,HTML5 最大的亮点是它为移动设备提供了一些非常有用的功能,使得 HTML5 具备了开发App的能力, HTML5开发App 最大的好处就是跨平台、快速迭代和上线,节省人力成本和提高效率,因此很多企业开始对传统的App进行改造,逐渐用H5代替Native,到2015年的时候,市面上大多数App 或多或少嵌入都了H5 的页面。既然要用H5 来构建 App, 那View 层所做的事,就不仅仅是简单的数据展示了,它不仅要管理复杂的数据状态,还要处理移动设备上各种操作行为等等。因此,前端也需要工程化,也需要一个类似于MVC 的框架来管理这些复杂的逻辑,使开发更加高效。 注:Native(使用原生制作APP,即在基于目前的智能手机的操作系统(如安卓android、苹果IOS,另外还有 (windows phone) 的基础上,使用相应平台支持的开发工具和语言 ( 比如 iOS 平台支持 Xcode 和 Objective-C,安平台支持 Eclipse 和 Java) 编写的第三方移动应用程序,简称原生APP。) 但实际上,随着H5 的不断发展,人们更希望使用H5 开发的应用能和Native 媲美,或者接近于原生App 的体验效果: 1)开发者在代码中大量调用相同的 DOM API,处理繁琐 ,操作冗余,使得代码难以维护。 2)大量的DOM 操作使页面渲染性能降低,加载速度变慢,影响用户体验。 3)当 Model 频繁发生变化,开发者需要主动更新到View ;当用户的操作导致 Model 发生变化,开发者同样需要将变化的数据同步到Model 中,这样的工作不仅繁琐,而且很难维护复杂多变的数据状态。 MVVM(Model View ViewModel) 模式: 其实,早期jquery 的出现就是为了前端能更简洁的操作DOM 而设计的,但它只解决了第一个问题,另外两个问题始终伴随着前端一直存在。MVVM 的出现,完美解决了以上三个问题。MVVM 由 Model、View、ViewModel 三部分构成,Model 层代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑;View 代表UI 组件,它负责将数据模型转化成UI 展现出来,ViewModel 是一个同步View 和 Model的对象。 在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,而View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理(用到这种的有来自Google的AngularJS,还有Vue.js、Knockout、Ember.js)。 3、主流前端框架/库简介目前的流行前端框架/库有:Vue、React、Angular(三大霸主)以及Bootstrap、APICloud、jQuery等;(jQuery、React为库) Vue毫无疑问是当前最流行最火爆的前端框架之一。vue作为渐进式前端框架,由当时的谷歌工程师尤雨溪大神业余时间所写,一放到github就引起流行,github上点赞数百万。vue现在几乎作为前端必备框架,特点高效,灵活,稳定,功能强大,代码少,运行速度快,整个文件只有200多K。Vue所关注的核心是MVC模式中的视图层,同时,它也能方便地获取数据更新,并通过组件内部特定的方法实现视图与模型的交互。vue做了必须的事,又不会做职责之外的事。做为前端,不懂vue是不行了。 React是Facebook在2013年开源的前端框架,由于 React的设计思想极其独特,属于革命性创新,性能出众,代码逻辑却非常简单。所以,越来越多的人开始关注和使用,认为它可能是将来 Web 开发的主流工具。React主要用于构建UI。你可以在React里传递多种类型的参数,如声明代码,帮助你渲染出UI、也可以是静态的HTML DOM元素、也可以传递动态变量、甚至是可交互的应用组件。也就是说同一组人只需要写一次 UI ,就能同时运行在服务器、浏览器和手机。开发效率高,事半功倍。 AngularJS诞生于2009年,由Misko Hevery 等人创建,是为了克服HTML在构建应用上的不足而设计的。后为Google所收购。是一款优秀的前端JS框架,已经被用于Google的多款产品当中。AngularJS有着诸多特性,最为核心的是:MVC(Model–view–controller)、模块化、自动化双向数据绑定、语义化标签、依赖注入等等。2016年angular2正式被发布,在Anguar2.0之前的版本都叫做AngularJS(Angular2不是从Angular1升级过来的,Angular2是重写的)。 jQuery是一个快速、简洁的JavaScript库,是继Prototype之后又一个优秀的JavaScript代码库。jQuery设计的宗旨是写更少的代码,做更多的事情。它封装JavaScript常用的功能代码,提供一种简便的JavaScript设计模式,优化HTML文档操作、事件处理、动画设计和Ajax交互。代码十分精炼,代码量小,速度快,犀利。使用量非常大。 Bootstrap(react是Facebook开发的,那么做为Facebook的竞争对手,Twitter公司也不甘示弱,开源了Bootstrap。)是由美国Twitter公司的设计师Mark Otto和Jacob Thornton合作基于HTML、CSS、JavaScript 开发的简洁、直观、强悍的前端开发框架,使得 Web 开发更加快捷。Bootstrap提供了优雅的HTML和CSS规范,它即是由动态CSS语言Less写成。Bootstrap一经推出后颇受欢迎,一直是GitHub上的热门开源项目,包括NASA的MSNBC(微软全国广播公司)的Breaking News都使用了该项目。国内一些移动开发者较为熟悉的框架,如WeX5前端开源框架等,也是基于Bootstrap源码进行性能优化而来。Bootstrap 能给你的 Web 开发提供了时尚的版式,表单,buttons,表格,网格系统等等。 apicloud(包括api.js和api.css)专门为移动端APP开发而设计的框架,适应不同的移动设备,而且可以和其他框架一起引入项目中使用,非常灵活,优秀。 注:框架和库的区别 库(插件):是一种封装好的特定方法集合,对项目的侵入性较小,提供给开发者使用,控制权在使用者手中,如果某个库无法完成某些需求,可以很容易切换到其它库实现需求。 框架:是一套架构,会基于自身特点向用户提供一套相当完整的解决方案,而且控制权在框架本身;对项目的侵入性较大,使用者要按照框架所规定的某种特定规范进行开发,项目如果需要更换框架,则需要重新架构整个项目。 4、Vue与AngularJS、React区别 4.1、与AngularJS的区别相同点: 都支持指令:内置指令和自定义指令。 都支持过滤器:内置过滤器和自定义过滤器。 都支持双向数据绑定。 都不支持低端浏览器。 不同点: AngularJS的学习成本高,比如增加了Dependency Injection特性,而Vue.js本身提供的API都比较简单、直观。 在性能上,AngularJS依赖对数据做脏检查,所以Watcher越多越慢。 Vue.js使用基于依赖追踪的观察并且使用异步队列更新。所有的数据都是独立触发的。 对于庞大的应用来说,这个优化差异还是比较明显的。 4.2、与React的区别相同点: React采用特殊的JSX语法,Vue.js在组件开发中也推崇编写.vue特殊文件格式,对文件内容都有一些约定,两者都需要编译后使用。 中心思想相同:一切都是组件,组件实例之间可以嵌套。 都提供合理的钩子函数,可以让开发者定制化地去处理需求。 都不内置列数AJAX,Route等功能到核心包,而是以插件的方式加载。 在组件开发中都支持mixins的特性。 不同点: React依赖Virtual DOM,而Vue.js使用的是DOM模板。React采用的Virtual DOM会对渲染出来的结果做脏检查。 Vue.js在模板中提供了指令,过滤器等,可以非常方便,快捷地操作DOM。 5、Vue特性1) 轻量级的框架 Vue.js 能够自动追踪依赖的模板表达式和计算属性,提供 MVVM 数据绑定和一个可组合的组件系统,具有简单、灵活的 API 2) 双向数据绑定 声明式渲染是数据双向绑定的主要体现,同样也是 Vue.js 的核心,它允许采用简洁的模板语法将数据声明式渲染整合进 DOM。 3) 指令 Vue.js 与页面进行交互,主要就是通过内置指令来完成的,指令的作用是当其表达式的值改变时相应地将某些行为应用到 DOM 上。 4) 组件化 组件(Component)是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。 在 Vue 中,父子组件通过 props 传递通信,从父向子单向传递。子组件与父组件通信,通过触发事件通知父组件改变数据。这样就形成了一个基本的父子通信模式。 在开发中组件和 HTML、JavaScript 等有非常紧密的关系时,可以根据实际的需要自定义组件,使开发变得更加便利,可大量减少代码编写量。 组件还支持热重载(hotreload)。当我们做了修改时,不会刷新页面,只是对组件本身进行立刻重载,不会影响整个应用当前的状态。CSS 也支持热重载。 5) 客户端路由 Vue-router 是 Vue.js 官方的路由插件,与 Vue.js 深度集成,用于构建单页面应用。Vue 单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来,传统的页面是通过超链接实现页面的切换和跳转的。 6) 状态管理 状态管理实际就是一个单向的数据流,State 驱动 View 的渲染,而用户对 View 进行操作产生 Action,使 State 产生变化,从而使 View 重新渲染,形成一个单独的组件。 注:Vue必须在ES5版本以上的环境下使用,一些不支持ES5的旧浏览器中无法运行Vue。 6、Vue发展历史 时间事件2013年在 Google 工作的尤雨溪,受到 Angular 的启发,开发出了一款轻量框架,最初命名为 Seed 。2013年12月更名为 Vue,图标颜色是代表勃勃生机的绿色,版本号是 0.6.0。2014年01月24日Vue 正式对外发布,版本号是 0.8.0。2014年02月25日0.9.0 发布,有了自己的代号:Animatrix,此后,重要的版本都会有自己的代号。2015年06月13日0.12.0,代号Dragon Ball,Laravel 社区(一款流行的 PHP 框架的社区)首次使用 Vue,Vue 在 JS 社区也打响了知名度。2015年10月26日1.0.0 Evangelion 是 Vue 历史上的第一个里程碑。同年,vue-router、vuex、vue-cli 相继发布,标志着 Vue从一个视图层库发展为一个渐进式框架。2016年10月01日2.0.0 是第二个重要的里程碑,它吸收了 React 的虚拟 Dom 方案,还支持服务端渲染。自从Vue 2.0 发布之后,Vue 就成了前端领域的热门话题。2019年02月05日Vue 发布了 2.6.0 ,这是一个承前启后的版本,在它之后,将推出 3.0.0。2019年12月05日在万众期待中,尤雨溪公布了 Vue 3 源代码,目前 Vue 3 处于 Alpha 版本。2020年09月18日Vue发布了3.0.0版本(https://github.com/vuejs/vue-next/releases)中。但是目前官网上只有vue3.x-beta (测试版API) 二、Vue安装及环境配置在搭建vue的开发环境之前,一定一定要先下载node.js,vue的运行是要依赖于node的npm的包管理工具来实现,node可以在官网或者中文网里面下载。官网地址:https://nodejs.org/en/download/ 备注:windows7 环境下只能使用Node.js 12.x及以下版本,官网下载地址:https://nodejs.org/en/download/releases/ 1、windows下搭建vue开发环境1)在官网下载好需要的版本,我下载的版本为:node-v12.20.0-x64.msi,下载完成安装,安装完成在CMD中查看是否安装成功;
2)设置缓存文件夹 npm config set cache "D:\program files\nodejs\node_cache"设置全局模块存放路径(之后用命令npm install XXX -g安装以后模块就在D:\program files\nodejs\node_global里) npm config set prefix "D:\program files\nodejs\node_global"3)高版本的nmp(Node包管理器:Node Package Manager,服务器在国外)是自带的,由于在国内使用npm是非常慢的,推荐使用淘宝npm镜像。在cmd中输入安装命令: #安装命令 npm install -g cnpm --registry=https://registry.npm.taobao.org #删除命令 npm uninstall -g cnpm --registry=https://registry.npm.taobao.org4)设置环境变量 (设置环境变量可以使得住任意目录下都可以使用cnpm、vue等命令,而不需要输入全路径) 在PATH中新增:D:\program files\nodejs\node_global(新增完成后重新打开CMD) 5)安装Vue #安装Vue cnpm install vue -g6)安装vue命令行工具,即vue-cli 脚手架 如果只是简单的写几个Vue的Demo程序,那么你不需要Vue-Cli。Cli是(Command-Line Interface,翻译为命令行界面,俗称脚手架,他是官方发布的Vue.js项目脚手架,使用Vue-cli可以快速搭建Vue开发环境以及对应的webpack配置) 7)创建新项目:webpack-simple / webpack 打开开始菜单,输入 CMD,或使用快捷键 win+R,输入 CMD,敲回车,弹出命令提示符。打开你将要新建的项目目录; vue init webpack-simple这样的方式适合小项目,vue init webpack这样的方式适合中大型项目; 输入:vue init webpack-simple vue-test (注:vue init webpack-simple+项目名称 名称不能有大写字母)
输入:vue init webpack vue-test-big 8)项目生成情况 vue init webpack-simple vue-test 生成目录: vue init webpack vue-test-big 生成目录: 目录/文件说明build最终发布代码的存放位置 config配置目录,包括端口号等node_modules这是执行npm install后产生的,里面包含了Node.js和npm依赖文件以及后续安装的第三方组件或者功能src我们要开发的目录,用于存放页面相关的文件,基本上要做的事情都在这个目录里面src\assets图片文件目录,如:logosrc\components存放了一个组件文件src\router项目的路由src\App.vue主文件,项目的入口文件,可以直接将组件写在这里,而不使用components目录src\amin.js项目的核心文件static一般用于存放静态资源,如:图片、字体等.babelrc用来设置转码的规则和插件,一般情况下不需要设置9)安装工程依赖模块 vue-test: #切换到当前目前,一定切换进来: D:\vueTest>cd vue-test #运行cnpm install,下载当前项目所依赖的包,在目录下会生成node_modules D:\vueTest\vue-test>cnpm install #运行cnpm run dev,启动当前的项目 D:\vueTest\vue-test>cnpm run dev第一个简单版的vue的项目,就好了打开链接:http://localhost:8080/ vue-test-big: #切换到项目目录 D:\vueTest>cd vue-test-big #运行cnpm run dev,启动当前项目 D:\vueTest\vue-test-big>cnpm run dev10)使用Visual Studio Code来开发Vue程序(当然也可以使用HBuilderX) a)导入项目:File->Open Folder->vue-test-big b)打开集成终端(open integrated terminal):快捷键(Ctrl+`) c)运行命令(cnpm run dev) d)打开页面(http://localhost:8080/) 但是我们看到的是http://localhost:8080/#/,关于生成的URL地址http://localhost:8080/#/后面的/#/,是路由的hash和history之分,默认是hash模式,会有#,把mode改成history: vue 项目往往会搭配 vue-router 官方路由管理器,它和 vue.js 的核心深度集成,让构建单页面应用变得易如反掌。vue-router 默认为 hash 模式,使用 URL 的 hash 来模拟一个完整的 URL,所以当 URL 改变时,页面不会重新加载,只是根据 hash 来更换显示对应的组件,这就是所谓的单页面应用。 //只需要在index.js加上一行mode: 'history', export default new Router({ // 路由模式:hash(默认),history模式 mode: 'history', //路由规则 routes:[ { path:'/', name:'index', component:'Index' } ], }) 2、如何使用Vue.js1)直接通过script加载CDN文件或者直接加载本地vue.js文件 2)npm(vue- cli)基于npm管理依赖使用nmp(vue- cli)来安装Vue 即前面的Vue环境搭建,不过官方文档上说:我们不推荐新手直接使用 vue- cli ,尤其是在你还不熟悉基于 Node.js 的构建工具时。 二、Vue基础知识 1、Vue学习内容学习Vue不要在想着怎么操作DOM,而是想着如何操作数据。那么Vue做了什么,我们要学习什么,先来一张总结性质的思维导图(此图为Vue2.x版本): 2、数据绑定数据绑定是将数据和视图关联,当数据发生变化是,可以自定更新视图。 2.1、语法-插值:{{msg|表达式}}文本插值是最基本的形式,使用双大括号{{}},类似于Mustache(Mustache是一个logic-less(轻逻辑)模板解析引擎,它的优势在于可以应用在Javascript、PHP、Python、Perl等多种编程语言中。) {{msg|表达式}}标签将会被替换为 data 对象上对应的 msg 属性的值,也支持写入表达式(表达式是各种数值、变量、运算符的综合体)。 注意:Mustache 语法不能作用在 HTML 元素的属性上。 2.2、语法-使用指令插值指令是带有v-前缀的特殊特性,其值限定为绑定表达式,也就是JavaScript表达式和过滤器。指令的作用是当表达式值发生变化是,将这个变化也反映到DOM上。 ----------------Vue版本号:{{myversion}}-------------- 基本插值:{{msg}} 表达式:{{flag?1:0}} new Vue({ el:"#app", data:{ myversion:Vue.version, msg:"Hello World", flag:true, show:true //改成false将会隐藏 } }); 3、分隔符Vue.js中数据绑定的语法被涉及为可配置的。如果不习惯Mustache风格的语法,则可以自己设置。在Vue 1.x 中它定义在(src/config.js源码)里,但是在Vue2.x后有所改变。 全局使用:Vue.options.delimiters = ['语法格式']; 实例选项定义:delimiters:['语法格式’] #{msg} //Vue 1.x中的全局设置方式 // Vue.config.delimiters = ["${', '}"]; //Vue 2.x中的全局设置方式 Vue.options.delimiters = ['${', '}']; var vm = new Vue({ //在实例中使用选项设置的方式 delimiters:['#{','}'], el:"#app", data:{ msg:"Hello World" } }); 三、Vue指令前面的案例中我们已经接触到了一个指令v-show,这种带有前缀 v-的指令,用于表示它们是 Vue 提供的特殊特性。在Vue中还定义了许多这种的内置指令。 1、插入数据指令(v-text、v-html ) 1.1、v-text预期:string 详细:更新元素的 textContent。如果要更新部分的 textContent,需要使用 {{ Mustache }} 插值。 1.2、v-html预期:string 详细:更新元素的 innerHTML。 注意:内容按普通 HTML 插入 - 不会作为 Vue 模板进行编译。如果试图使用 v-html 组合模板,可以重新考虑是否通过使用组件来替代。 示例: {{msg}} var vm = new Vue({ el:"#app", data:{ msg:"Hello World", html:"我是v-html指令" } }); 2、条件渲染指令(v-show、v-if、v-else、v-else-if) 2.1、v-show预期:any 用法:根据表达式之真假值,切换元素的 display CSS property。当条件变化时该指令触发过渡效果。 2.2、v-if预期:any 用法:根据表达式的值的 truthiness 来有条件地渲染元素。在切换时元素及它的数据绑定 / 组件被销毁并重建。如果元素是 ,将提出它的内容作为条件块。当条件变化时该指令触发过渡效果。 注意:当和 v-if 一起使用时,v-for 的优先级比 v-if 更高。v-show是css切换,v-if是完整的销毁和重新创建使用频繁切换时用v-show,运行时较少改变时用v-if 2.3、v-else用法:不需要表达式,为 v-if 或者 v-else-if 添加“else 块”。 限制:前一兄弟元素必须有 v-if 或 v-else-if。 2.4、 v-else-if类型:any 用法:表示 v-if 的“else if 块”。可以链式调用。 限制:前一兄弟元素必须有 v-if 或 v-else-if。(2.1.0 新增) 示例: 我是v-show 你看见的是:v-if 你看见的是:v-else A B C Not A/B/C var vm = new Vue({ el:"#app", data:{ show:false, type:"C" } }); 3、循环渲染指令(v-for)预期:Array | Object | number | string | Iterable (2.6 新增) 用法:基于源数据多次渲染元素或模板块。此指令之值,必须使用特定语法 alias in expression 索引:{{i}}-->值:{{item}} 索引:{{i}}-->id:{{dx.id}}--Name:{{dx.name}} 索引:{{index}} --> 键:{{key}} 值:{{val}} var vm = new Vue({ el:"#app", data:{ list_sz:[1,2,3,4,5], list_dx:[{id:2,name:'李四'},{id:3,name:'王五'},{id:1,name:'张三'}], list_user:{ id:1, name:'Mike', age:22, gender:'男' } } }); 3.1、v-for :key的使用官网有一句:v-for 的默认行为会尝试原地修改元素而不是移动它们。要强制其重新排序元素,你需要用特殊 attribute key 来提供一个排序提示。 官方对key的解释:key 的特殊 attribute 主要用在 Vue 的虚拟 DOM 算法,在新旧 nodes 对比时辨识 VNodes。如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法。而使用 key 时,它会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。重复的 key 会造成渲染错误。 要解释key的作用,不得不先介绍一下虚拟DOM的Diff算法了。vue和react都实现了一套虚拟DOM,使我们可以不直接操作DOM元素,只操作数据便可以重新渲染页面。而隐藏在背后的原理便是其高效的Diff算法。
当页面的数据发生变化时,Diff算法只会比较同一层级的节点:如果节点类型不同,直接干掉前面的节点,再创建并插入新的节点,不会再比较这个节点以后的子节点了。如果节点类型相同,则会重新设置该节点的属性,从而实现节点的更新。 对于相同类型的节点更新,如下图:我们希望可以在B和C之间加一个F,Diff算法默认执行起来是这样的:即把C更新成F,D更新成C,E更新成D,最后再插入E,是不是很没有效率?
不用index做为key的原因也是如此,如果用index作为key,[1,2,3]那么删除第二项的时候,index就会从1,2,3变成1,2,index永远是连续的,同样无法解决上诉问题。 所以一句话,key的作用主要是为了高效的更新虚拟DOM。另外vue中在使用相同标签名元素的过渡切换时,也会使用到key属性,其目的也是为了让vue可以区分它们,否则vue只会替换其内部属性而不会触发过渡效果。 v-for :key的使用 添加 {{item.name}} new Vue({ el: '#app', data: { name:'', list: [{id: 1,name: '典韦'},{id: 2,name: '凯'},{id: 3,name: '虞姬'},{id:4,name:'蔡文姬'}] }, methods: { add:function(){ var thisd = this.list.length+1; console.log(thisd+this.name); this.list.unshift({id:+thisd,name: this.name}); this.name = '' } } }); 3.2、关于v-for对应的数组的更新Vue重写了这些方法,使得他们具备响应式更新 push() 方法可向数组的末尾添加一个或多个元素,并返回新的长度。pop() 方法用于删除并返回数组的最后一个元素。shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值。unshift() 方法可向数组的开头添加一个或更多元素,并返回新的长度。splice() 方法向/从数组中添加/删除项目,然后返回被删除的项目。sort() 方法用于对数组的元素进行排序。reverse() 方法用于颠倒数组中元素的顺序。 4、属性绑定指令(v-bind)缩写:: 预期:any (with argument) | Object (without argument) 参数:attrOrProp (optional) 修饰符: .prop - 作为一个 DOM property 绑定而不是作为 attribute 绑定。.camel - (2.1.0+) 将 kebab-case attribute 名转换为 camelCase。(从 2.1.0 开始支持).sync (2.3.0+) 语法糖,会扩展成一个更新父组件绑定值的 v-on 侦听器。用法:v-bind 主要用于属性绑定,比方你的class属性,style属性,value属性,href属性等等,只要是属性,就可以用v-bind指令进行绑定 动态地绑定一个或多个 attribute,或一个组件 prop 到表达式。 在绑定 class 或 style attribute 时,支持其它类型的值,如数组或对象。可以通过下面的教程链接查看详情。 在绑定 prop 时,prop 必须在子组件中声明。可以用修饰符指定不同的绑定类型。 没有参数时,可以绑定到一个包含键值对的对象。注意此时 class 和 style 绑定不支持数组和对象。 语法:v-bind:属性名.修饰符="属性值" 4.1、绑定普通属性attribute 4.2、动态特性名 4.3、内联字符串拼接 4.4、class 绑定对应class绑定官网给出的三种类型:class对象绑定、class数组绑定、class数组中嵌套对象绑定 4.4.1、class对象绑定 html传统写法 {{message}} {{message}}案例: .blue{color: blue;} .red{color: red;} .jc{font-weight:bold}{{name}} {{name}} var vm = new Vue({ el:"#app", data:{ name:"v-bind:class对象绑定", isBlue:true, isRed:false }, methods:{ getPClass:function(){ return {blue:this.isBlue,red:this.isRed} } } });效果图: 4.4.2、class数组绑定、class数组中嵌套对象绑定 数组语法 数组中嵌套对象案例: .blue{color: blue;} .red{color: red;} .jc{font-weight:bold;} .cl{font-size: 30px;}{{name}} 切换颜色 var vm = new Vue({ el:"#app", data:{ name:"v-bind:class对象绑定", cssArray:['blue','jc',{cl:true}] }, methods:{ changeColor:function(){ if(this.cssArray[0]!=='blue'){ //Vue响应式:数据发生变化后,会重新对页面渲染 //使用响应式的操作函数push/pop/shift/unshift/splice/sort/reverse this.cssArray.shift();//移除数组第一个元素 this.cssArray.unshift('blue');//加入元素到数组的头部 //这种写法不是响应式的,数据发生变化,但是页面颜色不会发生改变 //this.cssArray[0]='blue'; //unshift可以,原因在于:Vue中重写了Array中的这7个函数 }else{ this.cssArray.shift(); this.cssArray.unshift('red'); //this.cssArray[0]='red'; } } } });效果图: 4.5、style 绑定对于style绑定,官网给出了两种:style对象绑定、style数组绑定 案例: {{name}} {{name}} 增大字体 var vm = new Vue({ el:"#app", data:{ name:"v-bind:style绑定", fontSize:20, style1:{color:'red'}, style2:{fontWeight:'bold'} }, methods:{ addSize:function(){ this.fontSize++; } } });效果图: 4.6、prop 绑定—通过 prop 修饰符绑定 DOM 属性官网的解释:作为一个 DOM property 绑定而不是作为 attribute 绑定。 4.6.1、从DOM节点properties(属性),attributes(特性)说起 property 是 dom 元素在 js 中作为对象拥有的属性; attribute 是 dom 元素在文档中作为 html 标签拥有的属性; 我们可以认为 property 是一个 DOM 对象创建的时候就会初始化在对象中的一些属性(我们也可以自定义属性),而 attribute 是附在 HTML 文档中的某个元素上的特性,我们可以改变、删除、自定义一个特性,但是对 property 不可以,对于 DOM 内置的属性我们无法删除,也只能按照规定类型赋值,并且内置属性会在每次 DOM 对象初始化的时候产生,比如 name 属性,无论我们设置什么类型的值,最后返回的都是字符类型。但是对于我们自定义的 DOM 属性,则可以是任何 JS 支持的数据类型,而 attribute 的数据类型只能是字符串。 对于 html 的标准属性来说,attribute 和 property 是同步的,是会自动更新的,但是对于自定义的属性来说,他们是不同步的。 window.onload = function(){ var ipt = document.getElementById('app'); console.log(ipt);//HTMLInputElement console.log(ipt.attributes);//object NamedNodeMap //html自带的dom属性会自动转换成property,但是自定义的属性没有这个'权利' console.log(ipt.className); //hh console.log(ipt.addUserDefine); //打印 undefined console.log(ipt.name);//打印 "" 虽然没写,但是默认为"" //浏览器解析之前全都是特性,解析之后:标准特性的值将被解析并挂载到 DOM属性上, //非标准特性只可用DOM的 getAttribute 等方法取值。getAttribute(attr),attr是大小写不敏感的 console.log(ipt.getAttribute('addUserDefine'));//zidingyi }当浏览器解析:这段代码之后,一个HTMLInputElement对象将会被创建,这个对象包含了很多的properties,如:accept, accessKey, align, alt, attributes, autofocus, baseURI, checked, childElementCount, childNodes, children, classList, className, clientHeight等。 对于DOM节点对象,properties就是这个对象(ipt)的属性集,而attributes是这个对象(ipt)中名为attributes的一个属性。在这些properties中,我们可以看到:className: "hh",等HTMLInputElement中存在的属性,properties同样继承了(标准属性),而addUserDefine(非标准属性)却没有出现在js对象的property中。 如果我们修改了:property的值 window.onload = function(){ var ipt = document.getElementById('app'); console.log(ipt);//HTMLInputElement console.log(ipt.attributes);//object NamedNodeMap //html自带的dom属性会自动转换成property,但是自定义的属性没有这个'权利' console.log(ipt.className); //hh console.log(ipt.addUserDefine); //打印 undefined console.log(ipt.name);//打印 "" 虽然没写,但是默认为"" //浏览器解析之前全都是特性,解析之后:标准特性的值将被解析并挂载到 DOM属性上, //非标准特性只可用DOM的 getAttribute 等方法取值。getAttribute(attr),attr是大小写不敏感的 console.log(ipt.getAttribute('addUserDefine'));//zidingyi //如果设置的属性属于DOM元素本身所具有的标准属性,不管是通过ele.setAttribute还是ele.title的方式设置,都能正常获取。 //通过setAttribute设置的自定义属性,只能通过标准的getAttribute方法来获取;同样通过点号方式设置的自定义属性也无法通过 标准方法getAttribute来获取。 ipt.mytitle = 'initTitle'; console.log(ipt.value);//initTitle console.log(ipt.getAttribute('mytitle'));//null //使用setAttribute ipt.setAttribute('mytitle','newTitle'); console.log(ipt.mytitle);//initTitle }这就是prop 修饰符的真正意义所在:v-bind 默认绑定到 DOM 节点的 attribute 上,使用 .prop 修饰符后,会绑定到 property上。(attribute 设置的自定义属性会在渲染后的 HTML 标签里显示,property 不会:通过自定义属性存储变量,避免暴露数据防止污染 HTML 结构) 4.6.2、通过 prop 修饰符绑定 DOM 属性 案例: {{name}} 没有修饰符 var vm = new Vue({ el:"#app", data:{ name:"测试prop修饰符", inputData:"hello" } }); window.onload=function(){ var div = document.getElementById("pry"); var divs = document.getElementById("prn"); console.log(div.aaa); //hello console.log(div.getAttribute('aaa'));//null console.log(div.aaa==vm.inputData);//true console.log(divs.aaa);//undefined console.log(divs.getAttribute('aaa'));//hello console.log(divs.getAttribute('aaa')==vm.inputData);//true }DOM效果: 4.7、.camel 修饰符只有props和.prop会默认将kebab-case转化为camelCase,剩下的作为attribute的不会。而.camel修饰符正是针对attribute的。 原本 加camel修饰符 Vue.component('child',{ //props中传递的数据可以为驼峰式也可以为短横线式,他们在此处是相互转换的 //props:['my-message'], props:['myMessage'], //props中使用驼峰命名,则 template:'{{myMessage}} ' // 此处有限制,是字符串模板,{{ }}语法中不能是短横线连接方式。此处只能是驼峰命名方式。若为短横线的命名方式,则会报错。 }); new Vue({ el:"#app", data:{ msgText: 'aaa', message:'' } });效果图: 5、数据双向绑定指令(v-model)预期:随表单控件类型不同而不同。 限制: components修饰符: .lazy - 取代 input 监听 change 事件.number - 输入字符串转为有效的数字.trim - 输入首尾空格过滤用法:在表单控件或者组件上创建双向绑定。 案例: value:{{test}} lazy:{{msg}} trim:{{trm}} number:{{age}} A B C Selected: {{ selected }} small big Picked: {{ picked }} 选项一 选项二 选项三 Checked names: {{ checkedNames }} new Vue({ el: '#app', data: { test: '', msg:'', trm:'', age:'', selected: '', picked: '', checkedNames: [] } });效果: 6、事件绑定指令(v-on)缩写:@ 预期:Function | Inline Statement | Object 参数:event 修饰符: .stop - 调用 event.stopPropagation()。.prevent - 调用 event.preventDefault()。.capture - 添加事件侦听器时使用 capture 模式。.self - 只当事件是从侦听器绑定的元素本身触发时才触发回调。.{keyCode | keyAlias} - 只当事件是从特定键触发时才触发回调。.native - 监听组件根元素的原生事件。.once - 只触发一次回调。.left - (2.2.0) 只当点击鼠标左键时触发。.right - (2.2.0) 只当点击鼠标右键时触发。.middle - (2.2.0) 只当点击鼠标中键时触发。.passive - (2.3.0) 以 { passive: true } 模式添加侦听器用法:绑定事件监听器。事件类型由参数指定。表达式可以是一个方法的名字或一个内联语句,如果没有修饰符也可以省略。 用在普通元素上时,只能监听原生 DOM 事件。用在自定义元素组件上时,也可以监听子组件触发的自定义事件。 在监听原生 DOM 事件时,方法以事件为唯一的参数。如果使用内联语句,语句可以访问一个 $event property:v-on:click="handle('ok', $event)"。 从 2.4.0 开始,v-on 同样支持不带参数绑定一个事件/监听器键值对的对象。注意当使用对象语法时,是不支持任何修饰器的。 6.1、事件处理器6.1.1、绑定方法 案例: Add 1The button above has been clicked {{ counter }} times. Greet var vm = new Vue({ el:"#example-1", data:{ counter:0, name: 'Vue.js' }, methods: { greet: function (event) { // `this` 在方法里指向当前 Vue 实例 alert('Hello ' + this.name + '!') // `event` 是原生 DOM 事件 if (event) { console.log(event.target.tagName) } } } });效果: 6.1.2、使用内联 案例: Say hi www.baidu.com var vm = new Vue({ el:"#example-3", methods: { say: function (message) { alert(message) }, say2: function (message,event) { if (event) { //event.preventDefault()是通知浏览器不要执行与事件关联的默认动作,则a标签不会跳转链接 event.preventDefault() } alert(message) } } });效果: 6.2、事件修饰符在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。为了解决这个问题,Vue.js 为 v-on 提供了事件修饰符。 6.2.1、.stop、.prevent、.capture、.self ... ...案例: obj1 obj2 obj3 obj4 var vm = new Vue({ el:"#app", methods:{ stop_show:function(ev){ alert("我是执行stop_show方法") //注释掉这里会弹出两个 //ev.cancelBubble=true;//阻止事件冒泡 }, stop_show2:function(){ alert("我是执行stop_show2方法") } } }); var vm1 = new Vue({ el:"#app1", methods:{ prevent_show:function(ev){ alert("我是执行prevent_show方法") //等效于加了这个,加了该方法鼠标右击事件被屏蔽 // ev.preventDefault();//阻止默认行为 } } }); var vm2 = new Vue({ el:"#app2", methods: { doc: function () { //点击obj4的时候,弹出的顺序为:obj1、obj4、obj3; //由于1有capture修饰符,故而先触发事件,2有self修饰符不是自己不会触发 然后就是4本身触发,最后冒泡事件3触发。 this.id= event.currentTarget.id; alert(this.id) } } });6.2.1、.once、.passive ...案例: {{18+age}} var vm = new Vue({ el:"#app", data:{ age:"" }, methods:{ ageadd:function(){ this.age++ } } }); 6.3、按键修饰符在监听键盘事件时,我们经常需要检查详细的按键。Vue 允许为 v-on 在监听键盘事件时添加按键修饰符,记住所有的keyCode比较困难(有一些按键 [.esc 以及所有的方向键)]在 IE9 中有不同的 key 值, 如果你想支持 IE9,这些内置的别名应该是首选),所以Vue为最常用的键盘事件提供了别名: .enter:回车键.tab:制表键.delete (捕获“删除”和“退格”键):含delete和backspace键.esc:返回键.space:空格键.up:向上键.down:向下键.left:向左键.right:向右键2.1.0 新增: .ctrl.alt.shifta:在 Windows 系统键盘 meta 对应 Windows 徽标键 (⊞)
2.2.0 新增: .left:只当点击鼠标左键时触发。.right:只当点击鼠标右键时触发。.middle:只当点击鼠标中键时触发。2.5.0 新增: .exact 修饰符允许你控制由精确的系统修饰符组合触发的事件。 A A A注:可以通过全局 config.keyCodes 对象自定义按键修饰符别名:Vue.config.keyCodes.f1 = 112 案例: enter: tab: delete: esc: space: up: ctrl+Q: 鼠标右键: new Vue({ el: '#box', data: { }, methods:{ show:function(ev){ alert(ev.keyCode) } } }); new Vue({ el:"#app", data : { msg : '', right_style:{border:'solid 2px blue',height:'100px',width:'100px'} }, methods : { keys:function(key) { alert('您按下的是' + key); }, mouseclick:function(where){ alert('点击鼠标'+where+'键触发'); } } }); 7、其他指令(v-pre、v-once、v-slot、v-cloak) 7.1、v-pre不需要表达式,例如:{{ this will not be compiled }} 用法:跳过这个元素和它的子元素的编译过程。可以用来显示原始 Mustache 标签。跳过大量没有指令的节点会加快编译。 7.2、v-cloak不需要表达式,例如:[v-cloak] { display: none; }, {{ message }} 用法:这个指令保持在元素上直到关联实例结束编译。和 CSS 规则如 [v-cloak] { display: none } 一起用时,这个指令可以隐藏未编译的 Mustache 标签直到实例准备完毕。 作用:由于浏览器网速问题,Vue在渲染{{msg}}数据时可能会有延迟,这延迟的一瞬间{{msg}}会原样输出,如:原本输出的是 自如初,延迟的结果就是{{msg}}被原样输出了。可以使用v-text与v-cloak解决。v-text只会输出文本,不会对HTML进行解析,若要输出HTML内容,那么v-text有着明显的局限性,也不灵活。v-cloak解决闪屏的问题。使用该指令时,要为该指令加display:none的样式。 7.3、v-once不需要表达式 详细:只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。 This will never change: {{msg}} comment{{msg}} {{i}}案例: /** 为v-cloak指令设置样式 **/ [v-cloak] { display: none; } { webUrl }}--> {{ webUrl }} {{ webName }} This will never change: {{msg}} This will change: {{msg}} var vm=new Vue({ el:'#app', data:{ msg:'hello vue', webName:"个人博客" } });效果: 7.4、v-slot缩写:# 预期:可放置在函数参数位置的 JavaScript 表达式 (在支持的环境下可使用解构)。可选,即只需要在为插槽传入 prop 的时候使用。 参数:插槽名 (可选,默认值是 default) 限用于: 组件 (对于一个单独的带 prop 的默认插槽)用法:提供具名插槽或需要接收 prop 的插槽。 示例:后面用到了再介绍 Header content Default slot content Footer content {{ slotProps.item.text }} Mouse position: {{ x }}, {{ y }} 8、特殊 attribute(key、ref、is) 8.1、key预期:number | string | boolean (2.4.2 新增) | symbol (2.5.12 新增) 用法:最常见的用例是结合 v-for,前面也已经介绍过了。 它也可以用于强制替换元素/组件而不是重复使用它。当你遇到如下场景时它可能会很有用。 完整地触发组件的生命周期钩子触发过渡注:这个在过渡中再介绍 {{ text }} 8.2、ref预期:string 作用:ref 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件。 注:这个在组件中再介绍 hello 8.3、 is预期:string | Object (组件的选项对象) 作用:用于动态组件且基于 DOM 内模板的限制来工作。 示例:这个在组件中再介绍 四、Vue实例及选项每个 Vue 应用都是通过用 Vue 函数创建一个新的 Vue 实例开始的。前面我们已经用了很多次 new Vue({...})的代码,而且Vue初始化的选项都已经用了data、methods、el等,估计,应该已经都明白了他们的作用。当一个 Vue 实例被创建时,它将 data 对象中的所有的 property 加入到 Vue 的响应式系统中。当这些 property 的值发生改变时,视图将会产生“响应”,即匹配更新为新的值。 Vue中支持很多选项,如下图所示:
Vue实例的基本结构: new Vue({ el:'#app',//所有的挂载元素会被 Vue 生成的 DOM 替换 data:{ },// this->window methods:{ },// this->vm //注意,不应该使用箭头函数来定义 method 函数 ,this将不再指向vm实例 props:{} ,// 可以是数组或对象类型,用于接收来自父组件的数据 //对象允许配置高级选项,如类型检测、自定义验证和设置默认值 watch:{ },// this->vm computed:{}, render:{}, }) 1、创建Vue实例 1.1、构造器vue实例的创建:一般通过new关键字的方式来创建,构造函数的参数列表需要传入一个选项对象 var vm = new Vue(paramObj); 1.2、创建Vue实例的三种方式Vue有三个属性和模板有关,官网上是这样解释的: el:提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标; template:一个字符串模板作为 Vue 实例的标识使用。模板将会 替换 挂载的元素。挂载元素的内容都将被忽略,除非模板的内容有分发插槽; render:字符串模板的代替方案,允许你发挥 JavaScript 最大的编程能力。该渲染函数接收一个 createElement 方法作为第一个参数用来创建 VNode; vue实例创建方式 {{msg}} new Vue({ el: "#app1", //用el做模板 data: { msg: "hello vue" } }) new Vue({ el: "#app2", data: { msg: "hello vue" }, template: "{{msg}} " //用template做模板 }) new Vue({ el: "#app3", data: { msg: "hello vue" }, render: function(h) { //直接用render函数渲染 return h('div', this.msg) } })效果: 2、 Vue实例化过程理解Vue 实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模板、挂载 Dom、渲染 → 更新 → 渲染、销毁等一系列过程,我们称这是 Vue 的生命周期,通俗说就是 Vue 实例从创建到销毁的过程。每一个组件或者实例都会经历一个完整的生命周期,总共分为三个阶段:初始化、运行中、销毁。四个主要过程:创建、挂载、更新、销毁。八个阶段(在这个过程中也会运行一些生命周期钩子):beforeCreate(创建前)、created(创建后)、beforeMount(挂载前)、mounted(载入后)、beforeUpdate(更新前)、updated(更新后)、beforeDestroy(销毁前)、destroyed(销毁后)。 引用官网一张图: 2.1、定义VueVue 构造函数只执行了 this._init(options) 这么一句代码。 function Vue (options) { if ("development" !== 'production' && !(this instanceof Vue) ) { warn('Vue is a constructor and should be called with the `new` keyword'); } this._init(options); } initMixin(Vue); // 定义 _init(初始化就已经加载了,里面定义了Vue的原型方法_init) stateMixin(Vue); // 定义 $set $get $delete $watch 等 eventsMixin(Vue); // 定义事件 $on $once $off $emit lifecycleMixin(Vue); // 定义 _update $forceUpdate $destroy renderMixin(Vue); // 定义 _render 返回虚拟dom 2.2、initMixin实例化Vue时,执行 _init, _init 定义在 initMixin 中,调用原型上的方法_init。这里主要做了这几件事情: 1)初始化 options 参数,将 _renderProxy 设置为 vm 2)生命周期变量初始化:vm.$parent vm.$root vm.$children vm.$refs等 3)初始化 渲染Render 4)初始化 vm的状态,prop/data/computed/method/watch都在这里完成初始化 5)挂载实例 Vue.prototype._init = function (options) { // 合并 options if (options && options._isComponent) { initInternalComponent(vm, options); // 组件合并 } else { // 非组件合并 vm.$options = mergeOptions( resolveConstructorOptions(vm.constructor), options || {}, vm ); } initLifecycle(vm); // 定义 vm.$parent vm.$root vm.$children vm.$refs 等(生命周期变量初始化) initEvents(vm); // 定义 vm._events vm._hasHookEvent 等(事件监听初始化) initRender(vm); // 定义 $createElement $c (初始化渲染) callHook(vm, 'beforeCreate'); // 回调 beforeCreate 钩子函数 initInjections(vm); // resolve injections before data/props (初始化注入) initState(vm); // 初始化 props methods data computed watch 等方法 (状态初始化) initProvide(vm); // resolve provide after data/props callHook(vm, 'created'); // 回调 created 钩子函数 // 如果有el选项,则自动开启模板编译阶段与挂载阶段 // 如果没有传递el选项,则不进入下一个生命周期流程 // 用户需要执行vm.$mount方法,手动开启模板编译阶段与挂载阶段 if (vm.$options.el) { vm.$mount(vm.$options.el); // 实例挂载渲染dom } }; 2.3、$mountmount 调用 mountComponent函数,这里主要做了这几件事: 1)判断是否有render选项,如果有则直接构建虚拟DOM 2)如果没有render选项,则判断是否有template 或者el挂载了元素 3)回调挂载前函数beforeMount 4)执行vm._update(vm._render(), hydrating); 将虚拟dom转为真实的dom并挂载到页面 5)使用Watcher函数检测数据是否更新,如果有更新则回调更新前函数beforeUpdate和更新后函数updated,如果检测到已经没有虚拟DOM了,回调载入后函数。 Vue.prototype.$mount = function ( el, hydrating ) { el = el && inBrowser ? query(el) : undefined; return mountComponent(this, el, hydrating) }; function mountComponent ( vm, el, hydrating ) { vm.$el = el; if (!vm.$options.render) { //如果选项中没有render选项 vm.$options.render = createEmptyVNode; //如果有render选项就创建虚拟DOM { /* istanbul ignore if */ if ((vm.$options.template && vm.$options.template.charAt(0) !== '#') || vm.$options.el || el) {//在判断选项中是否有template选项 或者 el挂载元素 warn( 'You are using the runtime-only build of Vue where the template ' + 'compiler is not available. Either pre-compile the templates into ' + 'render functions, or use the compiler-included build.', vm ); } else { warn( 'Failed to mount component: template or render function not defined.', vm ); } } } callHook(vm, 'beforeMount');//回调 挂载前函数 var updateComponent; /* istanbul ignore if */ if (config.performance && mark) { updateComponent = function () { var name = vm._name; var id = vm._uid; var startTag = "vue-perf-start:" + id; var endTag = "vue-perf-end:" + id; mark(startTag); var vnode = vm._render(); mark(endTag); measure(("vue " + name + " render"), startTag, endTag); mark(startTag); vm._update(vnode, hydrating); mark(endTag); measure(("vue " + name + " patch"), startTag, endTag); }; } else { updateComponent = function () { vm._update(vm._render(), hydrating); //将虚拟dom转为真实的dom并挂载到页面 }; } // we set this to vm._watcher inside the watcher's constructor // since the watcher's initial patch may call $forceUpdate (e.g. inside child // component's mounted hook), which relies on vm._watcher being already defined new Watcher(vm, updateComponent, noop, { before: function before () { if (vm._isMounted && !vm._isDestroyed) { callHook(vm, 'beforeUpdate'); //回调更新前函数 } } }, true /* isRenderWatcher */); hydrating = false; // manually mounted instance, call mounted on self // mounted is called for render-created child components in its inserted hook if (vm.$vnode == null) { vm._isMounted = true; callHook(vm, 'mounted'); //mounted(载入后) } return vm } 3、实例选项DOM(el、template、render、renderError) 3.1、el类型:string | Element 限制:只在用 new 创建实例时生效 详细:提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标。可以是 CSS 选择器,也可以是一个 HTMLElement 实例。 如果在实例化时存在这个选项,实例将立即进入编译过程,否则,需要显式调用 vm.$mount() 手动开启编译。如果 render 函数和 template property 都不存在,挂载 DOM 元素的 HTML 会被提取出来用作模板。 3.2、template类型:string 详细:一个字符串模板作为 Vue 实例的标识使用。模板将会替换挂载的元素。挂载元素的内容都将被忽略,除非模板的内容有分发插槽。 3.3、render类型:(createElement: () => VNode) => VNode 详细:字符串模板的代替方案,允许你发挥 JavaScript 最大的编程能力。该渲染函数接收一个 createElement 方法作为第一个参数用来创建 VNode。 注:Vue 选项中的 render 函数若存在,则 Vue 构造函数不会从 template 选项或通过 el 选项指定的挂载元素中提取出的 HTML 模板编译渲染函数。 3.4、renderError(2.2.0 新增)类型:(createElement: () => VNode, error: Error) => VNode 详细:只在开发者环境下工作。
案例:在Vue实例创建中,就已经展示了三种模板创建方式。在Vue实例化过程介绍中,提到过如果没有el挂载元素,则需手动挂载。 new Vue({ render(h) { throw new Error('oops') }, renderError(h, err) {//只在开发环境使用 return h('pre', { style: { color: 'red' } }, err.stack) } }).$mount('#app')//手动挂载到app上效果: 4、实例选项数据(data、props、propsData、computed、methods、watch) 4.1、methods类型:{ [key: string]: Function } 详细:methods 将被混入到 Vue 实例中。可以直接通过 VM 实例访问这些方法,或者在指令表达式中使用。方法中的 this 自动绑定为 Vue 实例。 methods {{msg}}测试按钮 new Vue({ el:'#app', data:{msg:"Hello World!"}, methods:{ ChangeMessage:function(){this.msg="Hello Vue!";} } })methods源码分析:执行initState()过程中做了很多的初始化工作(初始化:props => methods =>data => computed => watch),如果有定义(if (opts.methods) { initMethods(vm, opts.methods); } ),则进行初始化 function initMethods (vm, methods) { var props = vm.$options.props; for (var key in methods) { { if (typeof methods[key] !== 'function') {//遍历methods对象,key是每个键,即函数名称 warn( "Method \"" + key + "\" has type \"" + (typeof methods[key]) + "\" in the component definition. " + "Did you reference the function correctly?", vm ); } if (props && hasOwn(props, key)) {//如果props中有同名属性,则报错 warn( ("Method \"" + key + "\" has already been defined as a prop."), vm ); } if ((key in vm) && isReserved(key)) {//如果key是以$或_开头则,也报错 warn( "Method \"" + key + "\" conflicts with an existing Vue instance method. " + "Avoid defining component methods that start with _ or $." ); } } vm[key] = typeof methods[key] !== 'function' ? noop : bind(methods[key], vm);//如果key对应的值不是null,则执行bind()函数,将其绑定到Function的原型上 } } 4.2、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 是对象而不是函数,当存在多个该组件时,引用的是相同的组件选项对象,组件操作data会互相影响。) {{msg}} var vm = new Vue({ el:"#app", data:{ msg:"hello vue" } }); //在组件中必须是函数 Vue.component( 'component-name', Vue.extend({ //The "data" option should be a function that returns a per-instance value in component definitions. data : function() { return {msg : 'hello vue'}; } }));data源码分析:执行initState()过程中,如果有 if (opts.data) {initData(vm);}则调用initData方法。data中的属性不能和methods和props重名,调用observe方法对数组和对象分别进行了响应式设置(get/set) function initData (vm) { var data = vm.$options.data; // 如果data是一个方法 就执行这个方法 data = vm._data = typeof data === 'function' ? getData(data, vm) : data || {}; if (!isPlainObject(data)) { data = {}; warn( 'data functions should return an object:\n' + 'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function', vm ); } // proxy data on instance var keys = Object.keys(data);// 所有定义的data的第一层的key var props = vm.$options.props;// 所有定义的props var methods = vm.$options.methods; // 所有定义的methods var i = keys.length; while (i--) {//判断是否和methods和props重名 var key = keys[i]; { if (methods && hasOwn(methods, key)) {// key不能和方法名相同 warn( ("Method \"" + key + "\" has already been defined as a data property."), vm ); } } if (props && hasOwn(props, key)) {// key不可以和props定义的名称相同 warn( "The data property \"" + key + "\" is already declared as a prop. " + "Use prop default value instead.", vm ); } else if (!isReserved(key)) {// 看看是不是以$_开头 如果是以他们开头的 就给你抛异常 proxy(vm, "_data", key);// 设置代理 } } // observe data observe(data, true /* asRootData */); // 走observe方法,响应式设置 } 4.3、computed类型:{ [key: string]: Function | { get: Function, set: Function } } 详细:计算属性将被混入到 Vue 实例中。所有 getter 和 setter 的 this 上下文自动地绑定为 Vue 实例。 注意如果你为一个计算属性使用了箭头函数,则 this 不会指向这个组件的实例,不过你仍然可以将其实例作为函数的第一个参数来访问。 计算属性的结果会被缓存,除非依赖的响应式 property 变化才会重新计算。注意,如果某个依赖 (比如非响应式 property) 在该实例范畴之外,则计算属性是不会被更新的。 computedcomputed={{sumab}} computed={{sumab}} methods={{sumabs()}} methods={{sumabs()}} 上官 飞燕 慕容 云海 长孙 无忌 var data={a: 1,b: 2,c: 3}; new Vue({ el: "#app", data: data, computed: { //不需要设定处理可以不写set方法 sumab: function() { console.log('这是cpmputed实现的a+b处理') return Number(this.a) + Number(this.b) } }, methods: { sumabs:function(){ console.log('这是methods实现的a+b处理') return Number(this.a) + Number(this.b) } } }) // [{"上官 飞燕"},{"慕容 云海"},{"长孙 无忌"}] new Vue({ el: "#app1", data: { firstName:"", lastName:"" }, computed: { //什么时候执行:初始化显示""相关的data属性发生变化及使用fullNamesx属性时 fullNamesx:{ get:function(){ console.log("get:"+this.firstName + ' ' + this.lastName); //计算属性中的get方法,方法的返回值就是属性值 return this.firstName + ' ' + this.lastName }, set: function (val) {//val=取到的结果值 console.log("set:"+val); var names = val.split(' '); if(names.length>=2){ this.firstName =names[0]; this.lastName = names[names.length - 1]; } } } } })效果: 源码分析:在initState()执行中,if (opts.computed) { initComputed(vm, opts.computed); }则调用initComputed。computed实际上就是watcher实现的 function initComputed (vm, computed) { // $flow-disable-line var watchers = vm._computedWatchers = Object.create(null);//存放computed的观察者 // computed properties are just getters during SSR var isSSR = isServerRendering(); for (var key in computed) { var userDef = computed[key]; var getter = typeof userDef === 'function' ? userDef : userDef.get; if (getter == null) { warn( ("Getter is missing for computed property \"" + key + "\"."), vm ); } if (!isSSR) { // create internal watcher for the computed property. //computed实际上就是watcher实现的,这个实例的参数分别为vm实例,上方得到的getter,noop为回调函数,watcheroptions配置 watchers[key] = new Watcher( //生成观察者(Watcher实例) vm, getter || noop, noop, computedWatcherOptions ); } // component-defined computed properties are already defined on the // component prototype. We only need to define computed properties defined // at instantiation here. if (!(key in vm)) { defineComputed(vm, key, userDef); //将 computed 属性添加到组件实例上,并通过 get、set 获取或者设置属性值,并且重定义 getter 函数 } else { if (key in vm.$data) { warn(("The computed property \"" + key + "\" is already defined in data."), vm); } else if (vm.$options.props && key in vm.$options.props) { warn(("The computed property \"" + key + "\" is already defined as a prop."), vm); } } } }扩展:methods与computed区别与总结 4.4、watch类型:{ [key: string]: string | Function | Object | Array } 详细:一个对象,键是需要观察的表达式,值是对应回调函数。值也可以是方法名,或者包含选项的对象。Vue 实例将会在实例化时调用 $watch(),遍历 watch 对象的每一个 property。 watchb = {{b}} {{array}} 点击改变数组 var vm = new Vue({ el:"#app", data: { a: 1, b: 6, c: { name: "JohnZhu" }, array:['zs','ls','ww','emz'], isRed:"black" }, watch: { //监测a的变化 a: function(val, oldVal) { console.log('new a: %s, old a: %s', val, oldVal) }, //监测b的变化 b: 'someMethod',// 方法名 array:{ //官网提示:在变更 (不是替换) 对象或数组时,旧值将与新值相同,因为它们的引用指向同一个对象/数组。Vue 不会保留变更之前值的副本。 handler:function(newVal,oldVal){ console.log(newVal+'--'+oldVal)//旧值与新值相同 }, deep:true, immediate:true }, //监听对象的属性变化 'c.name':function(val, oldVal){ console.log('new c.name: %s, old c.name: %s', val, oldVal); } }, methods: { someMethod: function() { this.isRed="red"; alert("b is changed"); }, changeB: function() { this.b++; }, addArray:function(){ this.array.push('66') } } }) vm.a = 2; // new: 2, old: 1效果: 4.5、props类型:Array | Object 详细:props 可以是数组或对象,用于接收来自父组件的数据。props 可以是简单的数组,或者使用对象作为替代,对象允许配置高级选项,如类型检测、自定义验证和设置默认值。 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 } } } }) 4.6、propsData类型:{ [key: string]: any } 限制:只用于 new 创建的实例中。 详细:创建实例时传递 props。主要作用是方便测试。 var Comp = Vue.extend({ props: ['msg'], template: '{{ msg }}' }) var vm = new Comp({ propsData: { msg: 'hello' } }) 5、实例选项生命周期钩子前面讲过实例的创建过程,每个 Vue 实例在被创建时都要经过一系列的初始化过程,同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。 5.1、beforeCreate类型:Function 详细:在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。 5.2、created类型:Function 详细:在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer),property 和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el property 目前尚不可用。 从created到beforeMount的过程中, 首先会判断vue实例中有没有el选项,如果有的话则进行下面的编译,但是如果没有el选项,则停止生命周期,直到vue实例上调用vm.$mount(el)。 如果有el,再判断是否有template参数,如果有,则把其当作模板编译成render函数,如果没有,则把外部的html作为模板编译。template中的模板优先级高于outer HTML模板。 在vue对象中还有一个render函数,它是以createElement作为参数,然后做渲染操作,而且我们可以直接嵌入JSX. 综合排名优先级:render函数选项 > template选项 > outer HTML. 5.3、beforeMount类型:Function 详细:在挂载开始之前被调用:相关的 render 函数首次被调用。该钩子在服务器端渲染期间不被调用。 5.4、mounted类型:Function 详细:实例被挂载后调用,这时 el 被新创建的 vm.$el 替换了。如果根实例挂载到了一个文档内的元素上,当 mounted 被调用时 vm.$el 也在文档内。该钩子在服务器端渲染期间不被调用。 注意 mounted 不会保证所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以在 mounted 内部使用 vm.$nextTick: mounted: function () { this.$nextTick(function () { // Code that will run only after the // entire view has been rendered }) } 5.5、beforeUpdate类型:Function 详细:数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。该钩子在服务器端渲染期间不被调用,因为只有初次渲染会在服务端进行。 5.6、updated类型:Function 详细:由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。该钩子在服务器端渲染期间不被调用。 当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改状态。如果要相应状态改变,通常最好使用计算属性或 watcher 取而代之。 注意 updated 不会保证所有的子组件也都一起被重绘。如果你希望等到整个视图都重绘完毕,可以在 updated 里使用 vm.$nextTick: updated: function () { this.$nextTick(function () { // Code that will run only after the // entire view has been re-rendered }) } 5.7、beforeDestroy类型:Function 详细:实例销毁之前调用。在这一步,实例仍然完全可用。该钩子在服务器端渲染期间不被调用。 5.8、destroyed类型:Function 详细:实例销毁后调用。该钩子被调用后,对应 Vue 实例的所有指令都被解绑,所有的事件监听器被移除,所有的子实例也都被销毁。该钩子在服务器端渲染期间不被调用。 vue生命周期学习 {{message}} 手动销毁 var vm = new Vue({ el: '#app', data: { message: 'Vue的生命周期' }, methods:{ destroy:function(){ this.$destroy()//手动销毁 console.log("我执行了呀!"); //销毁后解绑了app,再次改变message值,vue不再对此动作进行响应了 //如果注释掉:this.$destroy()则生效 this.message="Vue的生命周期2"; } }, beforeCreate: function() { console.group('------beforeCreate创建前状态------'); console.log("%c%s", "color:red", "el : " + this.$el); //undefined console.log("%c%s", "color:red", "data : " + this.$data); //undefined console.log("%c%s", "color:red", "message: " + this.message)//undefined console.log("data、computed、watch、methods和DOM都不能使用"); }, created: function() { console.group('------created创建完毕状态------'); console.log("%c%s", "color:red", "el : " + this.$el); //undefined console.log("%c%s", "color:red", "data : " + this.$data); //已被初始化 console.log("%c%s", "color:red", "message: " + this.message); //已被初始化 console.log("可以操作data、computed、watch、methods,但DOM还没挂载。通常在此进行页面初始化操作或简单的Ajax请求"); }, beforeMount: function() { console.group('------beforeMount挂载前状态------'); console.log("%c%s", "color:red", "el : " + (this.$el)); //已被初始化 console.log(this.$el); console.log("%c%s", "color:red", "data : " + this.$data); //已被初始化 console.log("%c%s", "color:red", "message: " + this.message); //已被初始化 }, mounted: function() { console.group('------mounted 挂载结束状态------'); console.log("%c%s", "color:red", "el : " + this.$el); //已被初始化 console.log(this.$el); console.log("%c%s", "color:red", "data : " + this.$data); //已被初始化 console.log("%c%s", "color:red", "message: " + this.message); //已被初始化 console.log("实例被挂载到DOM上。通常用于执行Ajax请求。"); }, beforeUpdate: function() { console.group('beforeUpdate 更新前状态===============》'); console.log("%c%s", "color:red", "el : " + this.$el); console.log(this.$el); console.log("%c%s", "color:red", "data : " + this.$data); console.log("%c%s", "color:red", "message: " + this.message); }, updated: function() { console.group('updated 更新完成状态===============》'); console.log("%c%s", "color:red", "el : " + this.$el); console.log(this.$el); console.log("%c%s", "color:red", "data : " + this.$data); console.log("%c%s", "color:red", "message: " + this.message); }, beforeDestroy: function() { console.group('beforeDestroy 销毁前状态===============》'); console.log("%c%s", "color:red", "el : " + this.$el); console.log(this.$el); console.log("%c%s", "color:red", "data : " + this.$data); console.log("%c%s", "color:red", "message: " + this.message); }, destroyed: function() { console.group('destroyed 销毁完成状态===============》'); console.log("%c%s", "color:red", "el : " + this.$el); console.log(this.$el); console.log("%c%s", "color:red", "data : " + this.$data); console.log("%c%s", "color:red", "message: " + this.message) } })效果: 在Vue的整个生命周期中,它提供了一系列的事件,可以让我们注册js方法,可以让我们达到控制整个过程的目的地。通俗说就是Vue实例从创建到销毁的过程,就是生命周期。以上这8个方法就是生命周期钩子函数。 5.9、activated类型:Function 详细:被 keep-alive 缓存的组件激活时调用。该钩子在服务器端渲染期间不被调用。 5.10、deactivated类型:Function 详细:被 keep-alive 缓存的组件停用时调用。该钩子在服务器端渲染期间不被调用。 5.11、errorCaptured(2.5.0+新增)类型:(err: Error, vm: Component, info: string) => ?boolean 详细: 当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传播。 5.12、其他(选项 / 资源、选项 / 组合、选项 / 其它)关于Vue的选项还有一些,如下(都将在介绍全局API/组件中的时候在讲解): 选项 / 资源:directives、filters、components 选项 / 组合:parent、mixins、extends、provide / inject 选项 / 其它:name、delimiters、functional、model、inheritAttrs、comments 五、Vue实例的属性和方法Vue 实例暴露了一些有用的实例属性与方法。这些属性与方法都有前缀 $,以便与代理的数据属性区分。 1、Vue实例属性-DOM访问(vm.$el) 1.1、vm.$el类型:Element 只读 详细:Vue 实例使用的根 DOM 元素。 {{ message }} var vm2 = new Vue({ el: "#app", data: { message: "hello vue." } }); console.log(vm2.$el); //vm2.$el === 原生js中document.getElementById("app") vm2.$el.style.color = "red"; //变成红色 2、Vue实例属性-数据访问(vm.$data、vm.$options、vm.$props) 2.1、vm.$data类型:Object 详细:Vue 实例观察的数据对象。Vue 实例代理了对其 data 对象 property 的访问。 {{ message }} var vm = new Vue({ el: "#app", data: { message: "hello vue." } }); console.log(vm.$data) //{__ob__: Observer} console.log(vm._data); //{__ob__: Observer} console.log(vm.$data == vm._data); //true //三种方式都可以访问到message console.log(vm.$data.message); //hello vue console.log(vm._data.message); //hello vue console.log(vm.message); //hello vue效果: 通过vm.$data.message、vm._data.message甚至是vm.message,都可以获取到message,实际上都是访问的vm._data.xxx。具体的实现可以参考这篇文章:https://blog.csdn.net/xiaoxianer321/article/details/112637956 2.2、vm.$options类型:Object 只读 详细:用于当前 Vue 实例的初始化选项。需要在选项中包含自定义 property 时会有用处 2.3、vm.$props(2.2.0 新增)类型:Object 详细:当前组件接收到的 props 对象。Vue 实例代理了对其 props 对象 property 的访问。 3、Vue实例属性-组件树访问(vm.$parent、vm.$root、vm.$children、vm.$refs) 3.1、vm.$parent类型:Vue instance 只读 详细:父实例,如果当前实例有的话。 3.2、vm.$root类型:Vue instance 只读 详细:当前组件树的根 Vue 实例。如果当前实例没有父实例,此实例将会是其自己。 3.3、vm.$children类型:Array 只读 详细:当前实例的直接子组件。需要注意 $children 并不保证顺序,也不是响应式的。如果你发现自己正在尝试使用 $children 来进行数据绑定,考虑使用一个数组配合 v-for 来生成子组件,并且使用 Array 作为真正的来源。 3.4、vm.$refs类型:Object 只读 详细:一个对象,持有注册过 ref attribute 的所有 DOM 元素和组件实例。 4、Vue实例属性-作用域/插槽(vm.$slots、vm.$scopedSlots、vm.$attrs、vm.$listeners) 4.1、vm.$slots类型:{ [name: string]: ?Array } 只读 响应性:否 详细:用来访问被插槽分发的内容。每个具名插槽有其相应的 property (例如:v-slot:foo 中的内容将会在 vm.$slots.foo 中被找到)。default property 包括了所有没有被包含在具名插槽中的节点,或 v-slot:default 的内容。 请注意插槽不是响应性的。如果你需要一个组件可以在被传入的数据发生变化时重渲染,我们建议改变策略,依赖诸如 props 或 data 等响应性实例选项。 4.2、vm.$scopedSlots类型:{ [name: string]: props => Array | undefined } 只读 详细:用来访问作用域插槽。对于包括 默认 slot 在内的每一个插槽,该对象都包含一个返回相应 VNode 的函数。vm.$scopedSlots 在使用渲染函数开发一个组件时特别有用。 注意:从 2.6.0 开始,这个 property 有两个变化: 1)作用域插槽函数现在保证返回一个 VNode 数组,除非在返回值无效的情况下返回 undefined。 2)所有的 $slots 现在都会作为函数暴露在 $scopedSlots 中。如果你在使用渲染函数,不论当前插槽是否带有作用域,我们都推荐始终通过 $scopedSlots 访问它们。这不仅仅使得在未来添加作用域变得简单,也可以让你最终轻松迁移到所有插槽都是函数的 Vue 3。 4.3、vm.$attrs(2.4.0 新增)类型:{ [key: string]: string } 只读 详细:包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件——在创建高级别的组件时非常有用。 4.4、vm.$listeners(2.4.0 新增)类型:{ [key: string]: Function | Array } 只读 详细:包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用。 5、Vue实例属性-其他(vm.$isServer) 5.1、vm.$isServer类型:boolean 只读 详细:当前 Vue 实例是否运行于服务器。 源码如下: //源码 Object.defineProperty(Vue.prototype, '$isServer', { get: isServerRendering }); var _isServer; var isServerRendering = function () { if (_isServer === undefined) { /* istanbul ignore if */ //对应源码var inBrowser = typeof window !== 'undefined'; 利用浏览器的全局对象 window 做区分,因为在 nodejs 环境下是没有 window 这个全局对象的 //对应源码var inWeex = typeof WXEnvironment !== 'undefined' && !!WXEnvironment.platform; //如果不是浏览器运行环境 不是微信运行环境 不是Node环境(Node顶层对象是global) if (!inBrowser && !inWeex && typeof global !== 'undefined') { // detect presence of vue-server-renderer and avoid // Webpack shimming the process //检测是否存在vue服务器渲染器并避免Webpack填充过程 _isServer = global['process'] && global['process'].env.VUE_ENV === 'server'; } else { _isServer = false; } } return _isServer }; 6、Vue实例方法-数据(vm.$watch、vm.$set、vm.$delete) 6.1、vm.$watch( expOrFn, callback, [options] )参数: {string | Function} expOrFn 要观测的属性{Function | Object} callback 可以是一个回调函数, 也可以是一个纯对象(这个对象要包含handle属性){Object} [options] {boolean} immediate immediate立即执行回调{boolean} deep deep指的是深度观测返回值:{Function} unwatch 用法:观察 Vue 实例上的一个表达式或者一个函数计算结果的变化。回调函数得到的参数为新值和旧值。表达式只接受简单的键路径。对于更复杂的表达式,用一个函数取代。 注意:在变更 (不是替换) 对象或数组时,旧值将与新值相同,因为它们的引用指向同一个对象/数组。Vue 不会保留变更之前值的副本。 6.1.1、要观测的属性{string | Function} firstName: lastName:fullName: {{fullName}} var vm=new Vue({ el:'#app', data:{ firstName:"Dell", lastName:"Lee", fullName:'Dell Lee', } }); //vm.$watch( expOrFn, callback, [options] ) //expOrFn-键路径 监听firstName的变化,并在控制台打印 vm.$watch('firstName',function (newVal,oldVal) { console.log(newVal); console.log(oldVal); }) //expOrFn-函数 监听两者的变化 vm.$watch( function () { this.fullName=this.firstName+' '+this.lastName; } )效果: 6.1.2、deep选项 为了发现对象内部值的变化,可以在选项参数中指定 deep: true 。 注意监听数组的变动不需要这么做。(前面解释过重写了数组的操作方法) firstName: lastName:fullName: {{fullName}} var vm=new Vue({ el:'#app', data:{ firstName:"Dell", lastName:"Lee", fullName:'Dell Lee', info:{ age:20, sex:'man' } } }); //vm.$watch( expOrFn, callback, [options] ) vm.$watch( 'info.age', //直接用键值指定,没有deep也可以找到 function (newVal,oldVal) { console.log("我没有deep,有键:"+newVal); } ) //函数中没有指定deep选项 vm.$watch( 'info', function (newVal,oldVal) { console.log("我没有deep,没有键:"+newVal.age); } ) //有deep选项:可深度观测 vm.$watch( 'info', function (newVal,oldVal) { console.log("我有deep:"+newVal.age); }, {deep:true} )效果: 注:不使用键值单独使用函数也可以原因在于第一个参数如果是函数,调用属性会直接调用get方法。 //..源码 if (typeof expOrFn === 'function') { this.getter = expOrFn } else { this.getter = parsePath(expOrFn) } this.value = this.get() } //..6.1.3、immediate选项 在选项参数中指定 immediate: true 将立即以表达式的当前值触发回调。 firstName: lastName:fullName: {{fullName}} var vm=new Vue({ el:'#app', data:{ firstName:"Dell", lastName:"Lee", fullName:'Dell Lee', info:{ age:20, sex:'man' } } }); //vm.$watch( expOrFn, callback, [options] ) vm.$watch( 'info', function (newVal,oldVal) { console.log(newVal.age); },{ deep:true,immediate: true } )效果: 6.2、vm.$set( target, propertyName/index, value )参数: {Object | Array} target{string | number} propertyName/index{any} value返回值:设置的值。 用法:这是全局 Vue.set 的别名。在 参考:Vue.set 6.3、vm.$delete( target, propertyName/index )参数: {Object | Array} target{string | number} propertyName/index用法: 这是全局 Vue.delete 的别名。 参考:Vue.delete 7、Vue实例方法-事件(vm.$on、vm.$once、vm.$off、vm.$emit) 7.1、vm.$on( event, callback )参数: {string | Array} event (数组只在 2.2.0+ 中支持){Function} callback用法: 监听当前实例上的自定义事件。事件可以由 vm.$emit 触发。回调函数会接收所有传入事件触发函数的额外参数。常用在子组件向父组件派发事件的时候。 7.2、vm.$emit( eventName, […args] )参数: {string} eventName[...args]用法:触发当前实例上的事件。附加参数都会传给监听器回调。示例:前面我们接触过v-on指令,v-on:可监听普通dom的原生事件;可监听子组件emit的自定义事件;vm.$on:监听当前实例的自定义事件。 触发事件 触发事件 new Vue({ el: '#app', data:{ msg1: "饭后要洗碗", msg2: "周末要一起看电影", msg3: "周末要出去逛街" }, created:function(){ this.$on('need_wash', this.handleEvent); //实例监听:need_wash this.$on(['need_other','need_wash'], this.handleEvents); //实例监听:need_other、need_wash }, methods: { handleEvent:function(es){ console.log(this.msg1,es); // }, handleEvents:function(es){ if(es == "emitother"){ console.log("handleEvents:"+this.msg2,es); // console.log("handleEvents:"+this.msg3,es); // }else{ console.log("handleEvents:"+this.msg1,es); // } }, emit:function(es){ this.$emit('need_wash', es.target.id); }, emitother:function(es){ this.$emit('need_other', es.target.id); } } })效果: 7.3、vm.$once( event, callback )参数: {string} event{Function} callback用法: 监听一个自定义事件,但是只触发一次。一旦触发之后,监听器就会被移除。 7.4、vm.$off( [event, callback] )参数: {string | Array} event (只在 2.2.2+ 支持数组){Function} [callback]用法:移除自定义事件监听器。 如果没有提供参数,则移除所有的事件监听器; 如果只提供了事件,则移除该事件所有的监听器; 如果同时提供了事件与回调,则只移除这个回调的监听器。 示例: 触发事件 触发事件 var vm = new Vue({ el: '#app', data:{ msg1: "饭后要洗碗", msg2: "周末要一起看电影", msg3: "周末要出去逛街" }, created:function(){ this.$once('need_wash', this.handleEvent); //只监听一次 this.$on(['need_other','need_wash'], this.handleEvents); //实例监听:need_other、need_wash }, methods: { handleEvent:function(es){ console.log(this.msg1,es); // }, handleEvents:function(es){ if(es == "emitother"){ console.log("handleEvents:"+this.msg2,es); // console.log("handleEvents:"+this.msg3,es); // }else{ console.log("handleEvents:"+this.msg1,es); // } }, emit:function(es){ this.$emit('need_wash', es.target.id); }, emitother:function(es){ this.$emit('need_other', es.target.id); } } }); // vm.$off(); //无参数时默认移除所有监听 vm.$off('need_other'); //移除事件need_other的所有监听 vm.$off('need_wash', vm.handleEvents); //指定只移除这个回调的监听器效果: 8、Vue实例方法-生命周期(vm.$mount、vm.$forceUpdate、vm.$nextTick、vm.$destroy) 8.1、vm.$mount( [elementOrSelector] )参数: {Element | string} [elementOrSelector]{boolean} [hydrating]返回值:vm - 实例自身 用法:如果 Vue 实例在实例化时没有收到 el 选项,则它处于“未挂载”状态,没有关联的 DOM 元素。可以使用 vm.$mount() 手动地挂载一个未挂载的实例。 如果没有提供 elementOrSelector 参数,模板将被渲染为文档之外的的元素,并且你必须使用原生 DOM API 把它插入文档中。 这个方法返回实例自身,因而可以链式调用其它实例方法。前面已经介绍过。 8.2、vm.$forceUpdate()用法:迫使 Vue 实例重新渲染。注意它仅仅影响实例本身和插入插槽内容的子组件,而不是所有子组件。 //源码 Vue.prototype.$forceUpdate = function(){ const vm = this; if(vm._watcher){ vm._watcher.update(); } } //vm._watcher就是实例的watcher,每当组件内依赖的数据发生变化时,都会自动触发实例中_watcher的update方法。 //vm.$forceUpdate是手动通知实例重新渲染。 8.3、vm.$nextTick( [callback] )参数: {Function} [callback]用法: 将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。它跟全局方法 Vue.nextTick 一样,不同的是回调的 this 自动绑定到调用它的实例上。 2.1.0 起新增:如果没有提供回调且在支持 Promise 的环境中,则返回一个 Promise。请注意 Vue 不自带 Promise 的 polyfill,所以如果你的目标浏览器不是原生支持 Promise (IE:你们都看我干嘛),你得自行 polyfill。 new Vue({ // ... methods: { // ... example: function () { // 修改数据 this.message = 'changed' // DOM 还没有更新 this.$nextTick(function () { // DOM 现在更新了 // `this` 绑定到当前实例 this.doSomethingElse() }) } } }) 8.4、vm.$destroy()用法: 完全销毁一个实例。清理它与其它实例的连接,解绑它的全部指令及事件监听器。 会触发 beforeDestroy 和 destroyed 的钩子。 在大多数场景中你不应该调用这个方法。最好使用 v-if 和 v-for 指令以数据驱动的方式控制子组件的生命周期。 六、Vue的全局配置与全局API 1、Vue的全局配置Vue.config是一个对象,包含 Vue 的全局配置。可以在启动应用之前修改下列属性,这部分用到在做介绍,直接引用官网的。 1.1、silent类型:boolean 默认值:false 用法:Vue.config.silent = true -->取消 Vue 所有的日志与警告。 1.2、optionMergeStrategies类型:{ [key: string]: Function } 默认值:{} Vue.config.optionMergeStrategies._my_option = function (parent, child, vm) { return child + 1 } const Profile = Vue.extend({ _my_option: 1 }) // Profile.options._my_option = 2 //自定义合并策略的选项。 //合并策略选项分别接受第一个参数作为父实例,第二个参数为子实例,Vue实例上下文被作为第三个参数传入。 1.3、devtools类型: boolean 默认值: true (生产版为 false) 用法: // 务必在加载 Vue 之后,立即同步设置以下内容 Vue.config.devtools = true //配置是否允许 vue-devtools 检查代码。开发版本默认为 true,生产版本默认为 false。生产版本设为 true 可以启用检查。 1.4、errorHandler类型:Function 默认值:undefined 用法: Vue.config.errorHandler = function (err, vm) { // handle error } //指定组件的渲染和观察期间未捕获错误的处理函数。这个处理函数被调用时,可获取错误信息和 Vue 实例。 //Sentry, an error tracking service, provides official integration using this option. 1.5、warnHandler(2.4.0 新增)类型:Function 默认值:undefined 用法: Vue.config.warnHandler = function (msg, vm, trace) { // `trace` 是组件的继承关系追踪 } //为 Vue 的运行时警告赋予一个自定义处理函数。注意这只会在开发者环境下生效,在生产环境下它会被忽略 1.6、ignoredElements类型:Array 默认值:[] 用法: Vue.config.ignoredElements = [ 'my-custom-web-component', 'another-web-component', // 用一个 `RegExp` 忽略所有“ion-”开头的元素 // 仅在 2.5+ 支持 /^ion-/ ] //须使 Vue 忽略在 Vue 之外的自定义元素 (e.g. 使用了 Web Components APIs)。否则,它会假设你忘记注册全局组件或者拼错了组件名称,从而抛出一个关于 Unknown custom element 的警告。 1.6、keyCodes类型:{ [key: string]: number | Array } 默认值:{} 用法: Vue.config.keyCodes = { v: 86, f1: 112, // camelCase 不可用 mediaPlayPause: 179, // 取而代之的是 kebab-case 且用双引号括起来 "media-play-pause": 179, up: [38, 87] //给 v-on 自定义键位别名。 } 1.7、performance(2.2.0 新增)类型:boolean 默认值:false (自 2.2.3 起) 用法:设置为 true 以在浏览器开发工具的性能/时间线面板中启用对组件初始化、编译、渲染和打补丁的性能追踪。只适用于开发模式和支持 performance.mark API 的浏览器上。 1.8、productionTip(2.2.0 新增)类型:boolean 默认值:true 用法:设置为 false 以阻止 vue 在启动时生成生产提示。 2、全局APIVue的全局API提供大量的功能。 2.1、Vue.extend( options )参数: {Object} options用法: 使用基础 Vue 构造器,创建一个“子类”。参数是一个包含组件选项的对象。 data 选项是特例,需要注意 - 在 Vue.extend() 中它必须是函数。其主要用来服务于Vue.component,用来生成组件。 Vue.extend(),说白了,有点类似java中的继承(父类与子类)的关系。extend,这个词对我们来说并不陌生,jQuery为开发插件就提供了两个方法(.jQuery.extend(object)、jQuery.fn.extend(object)); 前者为扩展jQuery类本身,后者为自身添加新的方法。Vue.extend()会返回一个子(Sub)构造函数,Sub类似于继承了Vue构造函数。 示例: const Com = Vue.extend({ template: '{{msg}}', data:function(){ //必须是函数 return { msg: 'Hello Vue.extend' } }, methods: { handleClick:function(){ this.msg = this.msg.split('').reverse().join('') } } }) var vmfb = new Com(); document.body.appendChild(vmfb.$mount().$el); console.log(vmfb.$data.msg);//Hello Vue.extend console.log(vmfb.$options);效果: 2.2、Vue.nextTick( [callback, context] )参数: {Function} [callback]{Object} [context]用法:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。 Vue是异步执行dom更新的,一旦观察到数据变化,Vue就会开启一个队列,然后把在同一个事件循环 (event loop) 当中观察到数据变化的 watcher 推送进这个队列。如果这个watcher被触发多次,只会被推送到队列一次。这种缓冲行为可以有效的去掉重复数据造成的不必要的计算和DOm操作。而在下一个事件循环时,Vue会清空队列,并进行必要的DOM更新。当你设置 vm.someData = 'new value',DOM 并不会马上更新,而是在异步队列被清除,也就是下一个事件循环开始时执行更新时才会进行必要的DOM更新。如果此时你想要根据更新的 DOM 状态去做某些事情,就会出现问题。为了在数据变化之后等待 Vue 完成更新 DOM ,可以在数据变化之后立即使用 Vue.nextTick(callback) 。这样回调函数在 DOM 更新完成后就会调用。 {{msg}} 改变值 var vm = new Vue({ el: "#app", data: { msg: "Hello nextTick" }, methods: { //$nextTick方法 changeTxt: function() { this.msg = "Hello nextTick Update"; //修改dom结构 this.$nextTick(function() { //使用vue.$nextTick()方法可以dom数据更新后延迟执行后续代码 var domTxt = document.getElementById('h').innerText; console.log(domTxt); //输出可以看到vue数据修改后并没有DOM没有立即更新 if(domTxt === "Hello nextTick") { console.log("文本data被修改后dom内容没立即更新"); } else { console.log("文本data被修改后dom内容被马上更新了"); //输出结果 } }); } } }) //全局方法:nextTick vm.msg = "Hello nextTick 全局方法" var domTxt = document.getElementById('h').innerText; //这个时候去操作DOM某些数据可能会无效 console.log(domTxt); //hello nextTick 这个时候并未取到新更新的值 Vue.nextTick(function () { // DOM 更新了 var domTxt = document.getElementById('h').innerText; //这个时候就是最新的了 console.log(domTxt); //Hello nextTick 全局方法 })效果: 2.3、Vue.set( target, propertyName/index, value )参数: {Object | Array} target{string | number} propertyName/index{any} value返回值:设置的值。 用法:向响应式对象中添加一个 property,并确保这个新 property 同样是响应式的,且触发视图更新。它必须用于向响应式对象上添加新 property,因为 Vue 无法探测普通的新增 property (比如 this.myObject.newProperty = 'hi')。 受 ES5 的限制,Vue.js 不能检测到对象属性的添加或删除。因为 Vue在初始化实例时将属性转为 getter/setter,所以属性必须在 data 对象上才能让 Vue转换它,才能让它是响应的。如:给对象新增一个data中没有的属性,或者通过数组下标新增时都无法让视图刷新。这时,就可以使用Vue.set()或者this.$set() {{i+'-'+it}} {{index+'-'+item}} 方法中添加属性 var sz = ["1","2","3",{name:"老王",age:18,sex:"男"}]; var vm = new Vue({ el: "#app", data: { msg:sz }, methods: { changedata: function() { this.msg[3].job = "自由职业new"; //this.msg.push("5"); //使用这个方法会更新,因为vue重写了数组的操作方法 //this.$set(this.msg,1,'two'); console.log(sz); } } }) //视图不会更新 vm.msg[4] = "4"; vm.msg[3].job = "自由职业"; console.log(vm.msg); // Vue.set(vm.msg, 1, 'two');效果: 2.4、Vue.delete( target, propertyName/index )参数: {Object | Array} target{string | number} propertyName/index仅在 2.2.0+ 版本中支持 Array + index 用法。目标对象不能是一个 Vue 实例或 Vue 实例的根数据对象。 用法: 删除对象的 property。如果对象是响应式的,确保删除能触发更新视图。这个方法主要用于避开 Vue 不能检测到 property 被删除的限制,但是你应该很少会使用它。这个与set是反向的操作。 {{i+'-'+it}} {{index+'-'+item}} 方法中添加属性 var sz = ["1","2","3",{name:"老王",age:18,sex:"男"}]; var vm = new Vue({ el: "#app", data: { msg:sz }, methods: { changedata: function() { this.msg[3].job = "自由职业new"; // this.msg.push("5"); //使用这个方法会更新,因为vue重写了数组的操作方法 delete this.msg[4]; // this.$delete(this.msg[4]); console.log(sz); } } }) //视图不会更新 sz[4] = "4"; sz[5] = "5"; console.log(vm.msg); // Vue.delete(vm.msg,4); //删除4效果: 2.5、Vue.directive( id, [definition] )参数: {string} id{Function | Object} [definition]用法:注册或获取全局指令。 // 注册全局 Vue.directive('my-directive', { bind: function () {}, inserted: function () {}, update: function () {}, componentUpdated: function () {}, unbind: function () {} }) // 注册 (指令函数) Vue.directive('my-directive', function () { // 这里将会被 `bind` 和 `update` 调用 }) // getter,返回已注册的指令 var myDirective = Vue.directive('my-directive') //注册局部 directives: { focus: { // 指令的定义 inserted: function (el) { el.focus() } } }前面我们用过很多v-指令。在Vue2.x 中,代码复用和抽象的主要形式是组件。然而,有的情况下,我们仍然需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令。 举个简单的栗子:设置一个焦点 {{msg}}聚焦: // 注册一个全局自定义指令 `v-focus` Vue.directive('focus', { // 当被绑定的元素插入到 DOM 中时…… inserted: function (el) { // 聚焦元素 el.focus() } }) var vm = new Vue({ el:"#app", data:{ msg:"vue directive" } })上面我们使用到了一个钩子函数:inserted,一个指令定义对象可以提供如下几个钩子函数 (均为可选): 指令钩子函数: bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。 inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。 update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新。 componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。 unbind:只调用一次,指令与元素解绑时调用。 钩子函数参数: 指令钩子函数会被传入以下参数: el:指令所绑定的元素,可以用来直接操作 DOM。binding:一个对象,包含以下 property: name:指令名,不包括 v- 前缀。value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"。arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。vnode:Vue 编译生成的虚拟节点。oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。 {{msg}}聚焦: // 注册一个全局自定义指令 `v-focus` Vue.directive('focus', { bind: function(el, binding, vnode){ //只需要执行一次的一些操作 el.style.background="#FFFDD6"; console.log("我是bind"); }, // 当被绑定的元素插入到 DOM 中时…… inserted: function (el) { // 聚焦元素 el.focus(); console.log("我是inserted"); }, update: function(){ //根据获得的新值执行对应的更新 console.log("我是update"); }, componentUpdated: function(){ //指令所在组件的 VNode 及其子 VNode 全部更新后调用 console.log("我是componentUpdated"); }, unbind: function(){ //做清理操作 //比如移除bind时绑定的事件监听器 console.log("我是unbind"); } }) var vm = new Vue({ el:"#app", data:{ msg:"vue directive" } })效果: 2.6、Vue.filter( id, [definition] )参数: {string} id{Function} [definition]用法:注册或获取全局过滤器。 //全局注册 // 注册 Vue.filter('my-filter', function (value) { // 返回处理后的值 }) // getter,返回已注册的过滤器 var myFilter = Vue.filter('my-filter') //局部注册 filters:{ myFilter:function(value){ value+='hello world' return value } }Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化。过滤器可以用在两个地方:双花括号插值和 v-bind 表达式 (后者从 2.1.0+ 开始支持)。过滤器应该被添加在 JavaScript 表达式的尾部,由“管道”符号指示: {{ message | capitalize }} {{ message | filterA | filterB }} {{ message | filterA('arg1', arg2) }}过滤器原理简述: {{message|myFilter}} //这个过滤器在模板编译后 _s(_f('myFilter')(message)) //_f这个函数是resolveFilter的别名:找到我们写的过滤器,并将参数传入进去并执行 //_s函数是toString函数的别名示例: 全局/局部过滤器:{{ message | capitalize | capitalizes}} 过滤器搜索: {{ item.name }} //注册全局过滤器 Vue.filter('capitalize', function (value) { if (!value) { return ''; } value = value.toString(); return value.charAt(0).toUpperCase() + value.slice(1); }) new Vue({ el: '#app', data: { message:"hello vue", list: [ {id: '1',name: 'AAA'}, {id: '2',name: 'BBB'}, {id: '3',name: 'CCC'}, {id: '4',name: 'AAA'}, {id: '5',name: 'BBB'}, {id: '6',name: 'DDD'} ], isSearch: '' // }, //局部过滤器,如果同名则会覆盖全局的 filters: { capitalizes: function (value) { if (!value){ return '' } value = value.toString() return value.slice(0,5)+value.charAt(6).toUpperCase() + value.slice(7); } }, //实现搜索功能 computed: { search:function(){ var arr=[]; for (var i=0;i |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |