免费最好网站建设,网站开发公司合作协议书,网页设计报告心得,九江建网站VUE3基础知识梳理 一、vue了解和环境搭建1.vue是什么#xff1a;cn.vuejs.org/vuejs.org2.渐进式框架3.vue的版本4.vueAPI的风格5.准备环境5.1.创建vue项目5.2.vue的目录结构 二、vue3语法1.干净的vue项目2.模板语法2.1 文本插值2.2属性绑定2.3条件渲染2.4列表渲染2.5通过key管… VUE3基础知识梳理 一、vue了解和环境搭建1.vue是什么cn.vuejs.org/vuejs.org2.渐进式框架3.vue的版本4.vueAPI的风格5.准备环境5.1.创建vue项目5.2.vue的目录结构 二、vue3语法1.干净的vue项目2.模板语法2.1 文本插值2.2属性绑定2.3条件渲染2.4列表渲染2.5通过key管理状态2.6事件处理2.7事件传参2.8事件修饰符2.9数组变化侦测2.10 计算属性2.11 class绑定2.12 style绑定2.13 侦听器2.14 表单输入绑定双向绑定2.15 模板引用获取DOM树 三、组件1 组件组成2 组件嵌套关系3 组件注册方式4 组件传递数据 props5 组件传递多种数据类型类型校验参数默认值5.1 类型校验5.2 组件传参默认值5.3 声明必填 7 组件事件和v-model8 组件事件配合v-model和watch实现父子组件数据的实时互传9 组件数据传递使用props进行子传父10 透传attributes11 插槽slots12 组件生命周期15 动态组件16 组件保持存活keep-alive/KeepAlive17 异步组件18 依赖注入 一、vue了解和环境搭建
官方文档https://cn.vuejs.org/guide/essentials/event-handling.html
1.vue是什么cn.vuejs.org/vuejs.org
Vue(发音为 vju:/类似 view) 是一款用于构建用户界面的JavaScript 框架。 它基于标准 HTML、CSS 和JavaScript 构建并提供了一套声明式的、 组件化的编程模型帮助你高效地开发用户界面。 无论是简单还是复杂的界面Vue 都可以胜任.
2.渐进式框架
渐进式框架 Vue 是一个框架也是一个生态。其功能覆盖了大部分前端开发常见的需求。但 Web 世界是十分多样化的 不同的开发者在 Web 上构建的东西可能在形式和规模上会有很大的不同。考虑到这一点Vue 的设计非常注重灵活性和“可以被逐步集成”这个特点。 根据你的需求场景你可以用不同的方式使用 Vue:
需构建步骤渐进式增强静态的 HTML在任何页面中作为 Web Components 嵌入单页应用(SPA单页面应用)全栈/服务端渲染(SSR)Jamstack /静态站点生成(SSG)开发桌面端、移动端、WebGL甚至是命令行终端中的界面
简单的来说就是vue可以是只使用一个页面也可以是整个项目所以叫渐进式框架这个点有点有意思现在大多是用于全部前端。
3.vue的版本
现在用的比较多的是vue2和vue3vue3涵盖了vue2的知识所以直接使用vue3不学习vue2是没有关系的。 如何判断vue的版本在vue项目中的package.json 中会声明vue的版本号
4.vueAPI的风格
选项式APIOptions API 使用选项式AP1我们可以用包含多个选项的对象来描述组件的逻辑例如 data 、 methods 和 mounted 。选项所定义的属性都会暴露在函数内部的 this 上它会指向当前的组件实例.script
export default {data() {return {count: 0}}methods: {increment() {this.count}},mounted(){console.log(The initial count is ${this.count}.)}
/script
template
button clickincrement选项式API: Count is: f count /button
/template组合式API 下面是组合式API代码示例这种代码在vue3中比较普遍。 主要区别1.需要导入vue的onMounted。感觉还是组合式API更好看些。 此外mounted这个好像是安装的意思这里不知道表示的是真正什么意思后面应该会介绍 有意思的是onMounted中的写法有点类似函数式编程啊 事实上选项式API是在组合式API的基础上实现的其实底层还是组合式API。关于vue的概念和基础知识他们是通用的。在生产系统中若是不需要使用构建工具或者打算主要在低复杂度的环境下使用vue例如渐进增强的场景中推荐采用选项式API当你打算用vue构建完整的应用例如单页应用推荐组合式API。
5.准备环境
必须node.js 15或者更高版本使用node -v 查看nodejs的版本nodejs于js有点类似于jvm于java的关系node.js只是编译时起作用
5.1.创建vue项目
在cmd或者window的powershell中进行操作cd到指定的目录下运行命令npm init vuelatest ,这里会使用最新版本的vue进行初始化出一个vue项目周次运行时提示安装create-vue3.7.1,正常安装即可。npm init vuelatest这个命令的作用是使用最新版本的Vue框架快速初始化一个Vue项目。它会执行以下几件事情:
1. 使用npm创建一个新的文件夹,名称默认为当前目录名。
2. 在这个文件夹内初始化一个npm项目,生成package.json文件。
3. 安装最新版本的Vue和相关依赖包作为开发依赖。
4. 创建基础的Vue代码结构和文件,例如main.js、App.vue等。
5. 根据项目类型预设好webpack或Rollup的配置文件。
6. 创建一个GIT仓库并做首次提交。所以使用这个命令可以非常快速地初始化一个标准的Vue项目设置,不需要自己搭建Vue开发环境和项目脚手架。它npm init vuelatest使用了Vue官方的vue/cli服务,可以确保初始化的项目结构和依赖是官方推荐的最佳实践。
非常适合快速创建一个Vue项目的原型或示例来学习和试用Vue。这里创建以后会有各种提示让我们输入项目名等选项如下
Project name : 输入vue的项目名注意绝对不能大写Add TypeScript是否添加一个ts选择NO即可。这是一个辅助js的工具可以支持ES6ES6是js的一种规范大部分脚本语言都拥有标准规范比如sql。脚本语言必须指明自己所实现的规范是哪个目前使用比较广的是ES6ECMAScript。Add jsx Support是否添加jsx语法支持选择NO即可Add Vue Router For Single Page Application Development是否为vue添加一个简单的路由页面这个真正项目是需要的。练手时可以选NO。Add Pinia For State Management? 是否添加Pinia作为状态管理真正项目应该也是需要练手的话直接NOAdd Vitest for Unit Testing是否添加Vitest作为单元测试练手选NOAdd Cypress for both Unit And End-to-End Testing? 测试相关不太清洗练手选noAdd ESlint for Code quality? 这里应该是添加根据ES代码规范进行代码质量检查这里yes应该比较好教程里选的no 创建完成后的截图如下 上图提示需要运行npm install 和 npm run dev。那这两个命令是干什么的呢
npm install npm是管理软件包的命令执行npm install 并不是安装npm而是会根据项目里的package.json中声明的vue项目依赖的软件包然后去下载对应软件。此外npm还可以用来管理代码的版本对vue项目进行打包等操作所以后面的命令就是将vue项目按dev环境进行打包。这里npm是从国外下载包会很慢有两种提速的方式一种是使用cnpm 进行下载这个得单独安装这里的源都是国内的另一种是直接更改远程仓库更改远程仓库即使npm下载也很快npm config set registry https://registry.npm.taobao.org/npm install 在执行就很快了npm run dev运行package.json中的dev指令一般使用dev指令编译测试环境信息当展示如下信息时表示我们打包dev环境已经成功了 下面可以直接访问图中的地址了http://localhost:5173/ 当页面展示如上内容说明我们已经打包部署成功了这是一个可以用来做为开发的vue环境了。
使用VSCODE打开上面创建的目录vue-study-one即可。安装插件Vue Language Features (Volar)
5.2.vue的目录结构 .vscode这是vscode这个ide的配置文件和其他没有关系node_modules: 当我们执行命令npm install 时会将package.json中的包下载到本地下载到哪里了呢就是node_modulespublic存放资源文件默认里面只有ico文件src这是源码目录也就是后续的主要工作空间src-assets: 这里存放的是css、图片等静态文件。src-components: 这是component自带的文佳都是些helloword若自建vue文件的话都会放在这里.gitignore: git的忽略文件忽略后不提交到gitindex.htmlhtml的默认页面课程中说这个文件不能动也不能改后续所有的文件多需要依赖他来运行。package.json: 在这里声明各种包的版本其中包含了vue的版本vite.config.js:vue的配置文件也是常用的文件。vite是什么npmnode package manager是用来管理vue依赖的三方包和vue包的组件还可以用来打包项目等操作。vite则是一个vue项目构建的框架 使用vite可以快速搭建vue项目有点类似于maven对于java却高于maven。
二、vue3语法
vue是一种基于html模板语法使我们能够声明式的将其组件实例的数据绑定到呈现的DOM上所有的VUE模板都是语法层面合法HTML可以被符合规范的浏览器和html解析器解析。
1.干净的vue项目
删除src下assets下的所有文件这里一般存放静态文件初始时并不需要删除assets下的文件后删除main.js中的css文件的导入main.js代码如下
import { createApp } from vue
import App from ./App.vue
createApp(App).mount(#app)删除src下components的所有文件这里的文件都是默认携带的vue文件没有啥用处直接删除删除components下文件后在app.vue中会报错需要我们删除多余内容只保留以下内容即可然后重新运行进入页面后为空就是正常的了app.vue如下script
/script
template
/template2.模板语法
2.1 文本插值
文本插值是最近本的数据绑定形式使用双花括号进行数据绑定如下
!-- 这里存放的是js代码区域 --
script// export 用以导出组件defalut在一个.vue中只能有一次支持其他地方的importvue里不能省略该模块因为会在main.js中导入这个App.vue export default{// export导出模块中data()为常用的函数主要用来做数据渲染。// data(){// return {// msg:文本插值显示的值2// }// }// 下面这种写法也是支持的类似于java里的函数式编程可以默认进行类型推导只有一个返回值可以不写return// 一个export中只能有一个data这是不同的写法都是支持的data: ()({msg:文本插值显示的值4,msg2:第二个文本插值参数5})}
/script
!-- template 标签内存放html页面信息 --
templateh3模板语法/h3p{{ msg }}/pP{{msg2}}/P
/template{{}} 会将值解析为纯文本支持哪些值的填充
正常使用data函数声明的变量都是支持使用{{}}进行获取的
支持三目运算法
支持加减乘除支持字段转化支持一切可以形成终态的态度
不支持在内部进行新属性新方法的声明不支持if(true)等
其实只要是单行的表达式都是支持的换行就不行了下面是一些支持的示例
!-- 这里存放的是js代码区域 --
script// export 用以导出组件defalut在一个.vue中只能有一次支持其他地方的importvue里不能省略该模块因为会在main.js中导入这个App.vue export default{// 下面这种写法也是支持的类似于java里的函数式编程可以默认进行类型推导只有一个返回值可以不写return// 一个export中只能有一个datadata:()({msg:文本插值1,msg2:文本插值2,number:10,flag:true,text:我是谁})}
/script
!-- template 标签内存放html页面信息 --
templateh3模板语法/h3p{{ msg }}/pP{{ msg2 }}/Pp{{ number10 }}/pp{{ flag?正确:错误 }}/pp{{ text.split().reverse().join() }}/p
/template下面是运行展示 注意1若是data中声明的变量中包含html信息{{}}默认是不解析为html的而是解析成纯文本若是想要解析成html信息需要在html元素中增加 v-html属性然后指向我们声明的变量如下不止p支持v-html属性v-html也不是只支持a标签其他标签同样是支持的最终的结果是v-html中的变量信息会被解析成当前标签内的子标签信息
!-- 这里存放的是js代码区域 --
script// export 用以导出组件defalut在一个.vue中只能有一次支持其他地方的importvue里不能省略该模块因为会在main.js中导入这个App.vue export default{// 下面这种写法也是支持的类似于java里的函数式编程可以默认进行类型推导只有一个返回值可以不写return// 一个export中只能有一个datadata:()({msg:文本插值1,msg2:文本插值2,number:10,flag:true,text:我是谁,tiao:a hrefhttps://www.baidu.com点击跳转百度/a})}
/script
!-- template 标签内存放html页面信息 --
templateh3模板语法/h3p{{ msg }}/pP{{ msg2 }}/Pp{{ number10 }}/pp{{ flag?正确:错误 }}/pp{{ text.split().reverse().join() }}/ph1 v-htmltiao/h1P v-htmltiao/P
/template2.2属性绑定
vue的文件是可以被其他vue文件导入的有点类似于html里的功能。引入其他html文件使用import引入后还需要再模板模块指定如何使用这个页面。
script setup
import HelloWorld from ./components/HelloWorld.vue
/script
templateHelloWorld/
/template这样HelloWorld.vue中的内容就默认被集成在了当前的vue文件中了我们开发可以都在HelloWorld.vue中进行。 这里的属性绑定是指html的属性绑定。我们若是像如下操作是可以的
scriptexport default{data:()({msg:我是文本插值})}
/script
templateP{{ msg }}/P
/template但是若是msg如果想要是html的一个属性则vue是无法正常识别的这就需要使用别的功能了如下是不可行的。
scriptexport default{data:()({msg:我是文本插值})}
/script
templateP{{ msg }}/PP calss{{ msg }}测试使用原始文本插值进行属性绑定/P
/template前端的debug可以看到源码是这样的 可以看到我们的class这个属性并没有能成功绑定到我们的变量msg。 那该如何做到属性绑定呢VUE中提供了v-bind前面还有一个v-html是用来将变量的html属性能正常解析出来的如下所示
scriptexport default{data:()({msg:我是文本插值,testClass:testclass,testId:testId})}
/script
templateP{{ msg }}/PP calss{{ msg }}测试使用原始文本插值进行属性绑定/Pp v-bind:idtestId v-bind:classtestClass测试/p
/template注意变量进行属性绑定时是不需要写双括号的他的写法也比较简单直观v-bind:属性“变量名” 直接在属性中填写变量名即可如果绑定的属性是null或者undefined则vue会将该属性移除。验证结果如下 v-bind:属性“变量名” 还支持进行简写简写写法 :属性“变量名” 属性绑定不仅支持单个变量的绑定还支持整个对象的绑定如下我们可以直接将一个对象使用v-bind对象来给到html标签
scriptexport default{data:()({msg:我是文本插值,testClass:testclass,testId:testId,attributeObject:{zhangsan:张三,lisi:李四}})}
/script
templateP{{ msg }}/PP calss{{ msg }}测试使用原始文本插值进行属性绑定/Pp :idtestId v-bind:classtestClass测试/pp v-bindattributeObject测试对象绑定到html属性/p
/template运行的截图如下这里的zhangsan和lisi都不是正经的p标签属性这里只是用来测试真正场景中可以使用idclasstitle等。
2.3条件渲染
就是vue中也提供了条件判断的语句有如下几种
v-ifv-elsev-else-ifv-show v-show 和v-if在功能是是相似的都可以用来做元素是否展示的条件渲染。但是他们的原理不同。余下的v-else、v-else-if、等都需要和v-if进行配合使用。下面看下v-if组合的使用:
script
export default{data:()({element:D})
}
/script
templateh1这里是v-if等的条件渲染学习页/h1p v-ifelementA我是A/pp v-else-ifelementB我是B/pp v-else-ifelementC我是C/pp v-else我是D/p
/template下面是运行截图可以发现不满足条件的p标签是完全没有被生成的这也是v-if和v-show的主要区别。 下面是v-show的使用
script
export default{data:()({element:D,flag:true,flag2:false})
}
/script
templateh1这里是v-if等的条件渲染学习页/h1p v-ifelementA我是A/pp v-else-ifelementB我是B/pp v-else-ifelementC我是C/pp v-else我是D/pp v-ifflag我是使用v-if时的标签页/pp v-showflag我是使用v-show时的标签页/pp v-showflag2我是使用v-show时的标签页2/p
/template在之前的场景中已经验证了若是v-if不满足是不会有标签生成的可以发现在上面代码中增加了v-show为false的场景根据下图可以看出此时是有v-show为false的标签的只是该标签display为none。这也就是v-if和v-show的区别了。所以若是属性值变化比较频繁推荐使用v-show若是只使用一次则使用v-if和v-show差别也不是多大所以说若是没有特殊情况一般使用v-show会更好些
2.4列表渲染
列表渲染使用 v-foritem in/of items的方式进行列表数据的展示这里既可以使用in也可以使用of他们是相同的v-for可以用来展示数组也可以用来展示对象下面是v-for用来处理数组数据时的示例代码
scriptexport default{data:()({customers:[{id:1001,name:张三,sex:男},{id:1002,name:李四,sex:女},{id:1003,name:王五,sex:男}]})}
/script
templateh1这是列表渲染的代码/h1div v-forcustomer in customersp{{ customer.id }}{{ customer.name }}{{ customer.sex }}/p/div
/template通过如上方式我们就可以将数组中的元素进行去除上面的数据是一个json类型的对象数组循环取出来的是customer我们还需要使用customer.的方式获取其真正的属性。此外还可以获取到数组的每次下标不过表达式需要这么写v-for“(customer,index) in customers”,然后遍历时就可以获取到当前数组元素的下标了如下
scriptexport default{data:()({customers:[{id:1001,name:张三,sex:男},{id:1002,name:李四,sex:女},{id:1003,name:王五,sex:男}]})}
/script
templateh1这是列表渲染的代码/h1div v-for(customer,index) in customersp{{ customer.id }}{{ customer.name }}{{ customer.sex }}{{ index }}/p/divdiv v-forcustomer in customersp v-forcus in customer/p/div
/template结果如下 此外v-for还支持对对象的遍历在进行对象渲染时可以只获取属性的value若是只有一个参数默认就是value若是三个参数则第一个是value第二个是key第三个是index如下所示
scriptexport default{data:()({customer:{id:1004,name:赵六,sex:女},customers:[{id:1001,name:张三,sex:男},{id:1002,name:李四,sex:女},{id:1003,name:王五,sex:男}]})}
/script
templateh1这是列表渲染的代码/h1div v-for(customer,index) in customersp{{ customer.id }}{{ customer.name }}{{ customer.sex }}{{ index }}/p/divp v-for(value,key,index) in customer{{ index }}{{ key }}:{{ value }}/p
/template下面是运行展示
2.5通过key管理状态
在说key之前必须接着说说v-forv-for在遍历集合时会默认有个行为若是集合元素的位置发生了变化vue做不到直接更换元素的位置而是使用“就地更新的策略来更新响应的DOM信息。这样其实是浪费了性能的因为完全可以做到调换位置解决问题的。key就是做这个事情的。key需要作为集合所在标签的一个属性html中是没有key这个属性的这个是vue才会具有的官方推荐任何时候都需要为集合声明一个key防止元素因位置调换造成的性能损耗。 下面是key的代码
scriptexport default{data:()({customers:[{id:1001,name:张三,sex:男},{id:1002,name:李四,sex:女},{id:1003,name:王五,sex:男}]})}
/script
templatediv v-for(customer,index) in customers v-bind:keycustomer.idp{{ index }}:{{ customer.name }}/p/div
/template如上代码为div标签增加了key属性使用了v-bind进行属性绑定因为不使用v-bind的话会把index解析成字符串而不是获取对应的实际值。增加了key以后vue会自动帮我们进行元素调换而不是采用就地更新的策略。那应该使用什么作为key呢上面的例子中使用的是customer.id真正应用中也应该使用这种对于集合的元素来说不会变化的值作为key这样才能更好的判断元素的现在的真正位置。
2.6事件处理
事件处理一般分为“内联事件处理器”和“方法事件处理器”其中内联事件处理器在实际中基本不会使用真正使用的都是方法事件处理器。 事件处理器使用元素 v-on:事件“”,来进行事件声明当双引号之间是一个有结果的操作时比如这种称为内联处理器当双引号内是一个方法时则被称为方法处理器。需要说的是v-on:事件“”,可以被简写为事件“”,这种写法比较简洁也是使用比较多的方式。 下面是内联处理器的写法代码
scriptexport default{data:()({count:0})}
/script
templateh1内联处理器/h1button v-on:clickcount点击/buttonp{{ count }}/p
/template工作中真正使用的肯定是方法处理器方法处理器代码如下
scriptexport default{data:()({count:0}),// vue 中 所有的方法都需要声明在methods中这是固定写法多个方法使用逗号隔开methods:{add(){console.log(点击了)this.count// 在vue中的data中声明的变量都可以使用this进行获取console.log(this.count)}}}
/script
templateh1方法事件处理器/h1!-- v-on:click 可以简化成click --button clickadd点击/buttonp{{ count }}/p
/template这里有几个重要的点需要说下代码本身很简单
vue 中 所有的方法都需要声明在methods对象中这是固定写法methods对象内部多个方法使用逗号隔开在vue中的data中声明的变量都可以使用this进行获取v-on:click 可以简化成click
2.7事件传参
事件传参就是将参数传递到方法内然后由方法进行操作
scriptexport default{data:()({customers:[{id:1001,name:张三,sex:男},{id:1002,name:李四,sex:女},{id:1003,name:王五,sex:男}]}),methods:{showName(name,e){console.log(name);alert(e);}}}
/script
templateh1这是方法事件传参/h1div v-forcustomer in customers :keycustomer.idp clickshowName(customer.name,$event){{ customer.name }}/p/div
/template这里有一点要着重说的 若是想要传递event则需要在调用时使用$event进行传递。传递event一般是需要进行事件处理不过vue提供了丰富的事件修饰符可以简化envent的写法下一节就是了常见的stop阻止冒泡prevent阻止默认事件once只调用一次等。
2.8事件修饰符
事件修饰符是相对于事件来说的正常情况下需要把事件传递给方法然后我们在方法内部对事件进行变更如event.preventDefault() 或 event.stopPropagation() 。不过vue为v-on提供了事件修饰符来对事件的编辑进行简洁化修饰符是使用点表示的指令后缀。事件修饰符都有哪些呢
stop: 这个修饰符用于阻止事件冒泡。当一个元素触发事件时该事件会向上冒泡影响其父元素的相同事件。使用.stop修饰符可以阻止事件继续向上冒泡。事件冒泡是指当一个元素上的事件被触发时该事件会沿着 DOM 树向上传播
逐级触发每个祖先元素上相同类型的事件。这意味着如果一个元素上发生了事件
其父元素、祖父元素及更高层级的祖先元素也会接收到相同类型的事件。通过事件冒泡我们可以在更高级别的容器元素上监听事件而不需要为每个子元素
都添加事件处理程序。这使得事件处理变得更加灵活和简化了代码结构。
例如如果一个按钮元素嵌套在一个 div 元素中并且都绑定了点击事件处理程序。
当点击按钮时按钮的点击事件将首先触发然后事件将向上传播到包含它的 div 元素上
进而可能触发 div 上的点击事件处理程序。
在实际开发中我们可以利用事件冒泡来实现事件委托Event Delegation。
通过将事件处理程序绑定到父元素上可以避免在子元素上添加大量的事件处理程序。
这对于动态生成的元素或具有大量子元素的列表非常有用。需要注意的是通过 event.stopPropagation() 方法可以阻止事件继续冒泡
即停止事件在 DOM 树中的传播。这在需要限制事件冒泡范围或避免多个处理程序同时触发时很有用。scriptexport default{data(){return{msg:哈哈哈}},methods:{methodA(){alert(A方法被触发了);},methodB(){alert(B方法被触发了);}}}
/script
templatep clickmethodA()p clickmethodB()我是字标签的点击/p/p
/template上述代码若是触发了子标签的点击则默认情况下methodA同样会被触发怎么解决这个问题呢使用stop就可以组织这种冒泡行为 上面的代码改成如下即可
scriptexport default{data(){return{msg:哈哈哈}},methods:{methodA(){alert(A方法被触发了);},methodB(){alert(B方法被触发了);}}}
/script
templatep clickmethodA()!-- stop禁止事件的冒泡 --p click.stopmethodB()我是字标签的点击/p/p
/template.self这个修饰符只有在事件在原始元素本身上触发时才会触发事件处理程序。如果事件是从子元素冒泡到父元素并触发的那么使用.self修饰符的父元素将不会被正常冒泡。self是从自身禁止冒泡stop则是从子元素来禁止冒泡他们想达到的目的类似但作用的对象不同scriptexport default{data(){return{msg:哈哈哈}},methods:{methodA(){alert(A方法被触发了);},methodB(){alert(B方法被触发了);}}}
/script
templatep click.selfmethodA()!-- stop禁止事件的冒泡 --p clickmethodB()我是字标签的点击/p/p
/template疑问self是否是直接中断事件的向上冒泡还是只是绕过了自己div clickmethodCdiv click.selfmethodBp clickmethodA我是孙子级点击事件按钮/p/div
/div如上当有三个层级的单点事件时self只会阻止自身的冒泡事件但不会阻止冒泡事件的向上传递 当把这里的 self换成stop时是什么效果呢其实是正常输出A、B方法的内容不会输出C。因为stop是停止向上冒泡但不禁止自身的事件触发。.prevent这个修饰符用于阻止事件的默认行为。例如当你在一个表单中提交时页面会重新加载。使用.prevent修饰符可以阻止表单的默认提交行为。 这里我的理解是prevent阻止的是dom的默认行为。不知道理解的对不对如下案例点击时会调用方法a但不会跳转百度a hrefhttp://www.baidu.com click.preventmethodA()点我进百度测试prevent/a.once这个修饰符用于只触发一次事件处理程序。当事件被触发后事件处理程序将被移除不会再次触发。p dblclick.oncemethodA()点击我测试once/p经验证确实只会被触发一次再继续点击就再也不会触发了刷新以后才可以恢复..capture这个修饰符用于将事件监听器添加到父元素上并在事件捕获阶段触发。默认情况下事件监听器是在事件冒泡阶段触发的。使用.capture修饰符可以将事件监听器切换到事件捕获阶段。.passive这个修饰符可以提高滚动性能。当你在一个滚动事件的监听器中使用.passive修饰符时告诉浏览器该事件处理程序不会调用preventDefault()来阻止默认的滚动行为。这样浏览器可以进行一些优化提高滚动的性能。 除了这些事件修饰符以外还有很多键盘等其他修饰符详见官网https://cn.vuejs.org/guide/essentials/event-handling.html#event-modifiers
2.9数组变化侦测
这里主要是两类关于数组的方法一类操作数组时会直接引起数组内容的变化无需我们作额外操作数据的数据就会动态展示在页面中这类操作有 push添加一个元素到数组中不能一次性添加多个 pop从尾部将数组的元素进行删除一个一次只能删除一个 shift从头部将数组的元素进行删除一个一次只能删除一个 unshift从头部插入一个或者多个元素 splice(start, deleteCount, item1, item2, …): splice 方法用于修改数组可以用于删除、替换或插入元素。它会修改原始数组并返回被删除的元素数组。其中start 是指要修改的起始索引位置deleteCount 是要删除的元素个数可选的 item1, item2, … 是要插入到数组的元素。例如 fruits [Apple, Banana, Orange];
fruits.splice(1, 1, Strawberry, Mango);
修改后的数组为 [Apple, Strawberry, Mango, Orange]sortsort 方法用于原地对数组进行排序。默认情况下它按照 Unicode 字符编码的顺序进行排序。如果想要自定义排序逻辑可以提供一个比较函数作为参数。例如 numbers [3, 1, 5, 2, 4];
numbers.sort();
排序后的数组为 [1, 2, 3, 4, 5]
也可以传入一个比较器进行比较
this.months.sort((a,b){if(ab){return 1;}else if(ab){return -1;}else{return 0;}});
上面的排序是倒叙排按正常左减右的相反结果进行返回reversereverse 方法用于反转数组中元素的顺序。它会修改原始数组并返回修改后的数组。例如 fruits [Apple, Banana, Orange];
fruits.reverse();
修改后的数组为 [Orange, Banana, Apple]注意的是上面的这些方法操作完数组以后数组会自动变化无需我们再像下面这样操作如果操作了反而不对。 这种写法是错误的
this.months this.months.reverse(); 还有另一种数组的操作这种操作都会产生一个新的数组所以我们必须使用原数据进行接着不然数据的变更无法更新到dom中 filter起到一个过滤的作用这里的用法与java里的strem的filter很是类似如下所示 this.monthsthis.months.filter((month){return monthmarch;})执行此操作后数组里将只会剩下一个marchconcat顾名思义就是拼接一个新的数组到原数组中操作如下 this.months this.months.concat([june,july]);
默认是在尾部进行拼接元素如果想拼接在头部可以先这么写验证了下是ok的
this.months this.months.reverse().concat(june,july).reverse();sliceslice是片的意思他的作用是从原数组中取出一部分作为一个新的数据操作如下 this.months this.months.slice(0,2);
上面的操作是获取0下标开始2下标结束的元素注意不包括2然后组成一个新的数组2.10 计算属性
这里需要学习一个在export中的新的小模块computed对象他和methods一样也是对象他是专门为属性计算设计的先来看下不使用属性计算时如何写
scriptexport default{data(){return {customer:{id:1001,name:张三,address:[住址1,住址2,住址3]}}}}
/script
templateh1这是计算属性Computed的学习页/h1p v-for(value,key,index) in customer v-bind:keycustomer.idp{{ customer.address.length0?非空:空 }}/p/p
/template可以看到这把计算写在了双阔号内这么写语法上是允许的但是会发现若是表达式比较多就会比较混乱所以官方推荐以方法的形式写在computed对象内同时computed内部的方法不支持传参因为computed总的计算结果会被缓存若是计算内的值不变则不会触发重新计算这样更有利于性能而若是使用方法方法每次都会进行重新计算所以感觉computed和methods在使用上差不多但是性能上是有区别的这也是computed存在的原因下面是使用三种方式的代码展示
scriptexport default{data(){return {customer:{id:1001,name:张三,address:[住址1,住址2,住址3]}}},// computed中的方法不支持传参因为需要缓存计算结果传参的话则结果不可控就无法缓存这样的话与方法就没有区别了computed:{computedTest(){return this.customer.address.length0?非空:空;}},methods:{methodTest(){return this.customer.address.length0?非空:空;}}}
/script
templateh1这是计算属性Computed的学习页/h1p v-for(value,key,index) in customer v-bind:keycustomer.id/pp原生写法{{ customer.address.length0?非空:空 }}/ppcomputed写法{{ computedTest }}/ppmethods写法{{ methodTest() }}/p
/template下面是运行截图可以发现三种方式都能达到效果但是性能最好的是computed的写法 注意
computed会将内部方法计算的结果进行缓存数据不变化就不会触发重新计算computed的方法不支持传参若是传了参则结果就是动态的就无法缓存methods的触发每次都会进行重新计算所以性能上computed高于methods{{}} 双阔号内支持调用计算属性无需加{{}} 双阔号内支持调用方法但是方法必须加()
2.11 class绑定
html中标签支持class属性class属性用于指定一个或多个 CSS 类名将这些类名应用于元素多个css类名使用空格进行分割他们共同对当前的html的标签进行生效。
单值绑定 代码如下无论是单值绑定还是多值绑定都必须为其声明css类因为我们传给html的class属性的是字符串他会把其解析成css的class类名然后去style或者引入的css文件中去寻找对应的class找不到就没有样式。scriptexport default{data(){return{color:classA}}}
/script
style.classA{color:rgb(230, 71, 71);font-size: 30px;}
/style
templateh1验证class绑定/h1!-- v-bind:属性 可以简写为 :属性比较常见的是 :class :id :key --p v-bind:classcolor单值绑定/p
/template多值绑定 和 数组绑定 其实vue是不支持多值绑定的vue里的class多值绑定需要使用数组来完成原始的html中class中若是声明多个css类名需要使用空格隔开但是vue中属性绑定不支持直接写多个如果写多个需要以数组的形式进行绑定不然就只能写原生html的写法scriptexport default{data(){return{color:classA,colorB:classB,font:fontA}}}
/script
style.classA{color:rgb(230, 71, 71);font-size: 30px;}.classB{color: rgb(230, 71, 71);}.fontA{font-size: 30px;}
/style
templateh1验证class绑定/h1!-- v-bind:属性 可以简写为 :属性比较常见的是 :class :id :key --p v-bind:classcolor单值绑定/pp v-bind:class[colorB,font]多值绑定/p
/template对象绑定 对象绑定有两种形式一种是内联的写法也就是直接在class中写对象一种是外部声明的对象不过对象的写法和直接声明值表示有区别使用对象时对象的属性表示css中class的类名对象的属性值应为boolean类型表示是否启用下面是class绑定的对象内联的写法scriptexport default{data(){return{color:classA,colorB:classB,font:fontA,classObject:{color:classB,font:fontA}}}}
/script
style.classA{color:rgb(230, 71, 71);font-size: 30px;}.classB{color: rgb(230, 71, 71);}.fontA{font-size: 30px;}
/style
templateh1验证class绑定/h1!-- v-bind:属性 可以简写为 :属性比较常见的是 :class :id :key --p v-bind:classcolor单值绑定/pp v-bind:class[colorB,font]多值绑定/pp v-bind:class{classB:true,fontA:true}对象绑定/p
/template下面是对象绑定时在data中声明的对象其实没区别就是把上面的写法挪到data中了不过需要注意的是这里对象的属性都是css的类名和一开始属性是变量名不同了。从下面可以看到内联和非内联的写法的区别内联时对象是应该有中括号包裹的非内联直接传入对象名即可scriptexport default{data(){return{color:classA,colorB:classB,font:fontA,classObject:{classB:true,fontA:false}}}}
/script
style.classA{color:rgb(230, 71, 71);font-size: 30px;}.classB{color: rgb(230, 71, 71);}.fontA{font-size: 30px;}
/style
templateh1验证class绑定/h1!-- v-bind:属性 可以简写为 :属性比较常见的是 :class :id :key --p v-bind:classcolor单值绑定/pp v-bind:class[colorB,font]多值绑定/pp v-bind:class{classB:true,fontA:true}对象绑定-内联/pp v-bind:classclassObject对象绑定-非内联/p
/template数组嵌套对象进行class属性绑定 数组内部是可以嵌套对象的但是对象内部是不能嵌套数组的。这种写法其实很好理解数组中只能传入我们声明的变量名而不是css的类名这是数组和对象使用的最大区别。 对象也是我们声明的变量故都可以直接传入到数组中scriptexport default{data(){return{color:classA,colorB:classB,font:fontA,classObject:{classB:true,fontA:false},leftsize:left}}}
/script
style.classA{color:rgb(230, 71, 71);font-size: 30px;}.classB{color: rgb(230, 71, 71);}.fontA{font-size: 30px;}.left{margin-left: 100px;}
/style
templateh1验证class绑定/h1!-- v-bind:属性 可以简写为 :属性比较常见的是 :class :id :key --p v-bind:classcolor单值绑定/pp v-bind:class[colorB,font]多值绑定/pp v-bind:class{classB:true,fontA:true}对象绑定-内联/pp v-bind:classclassObject对象绑定-非内联/pp :class[classObject,leftsize]对象绑定嵌套数组绑定/p
/template2.12 style绑定
html中的标签支持class属性用以对应css中的类名同时也支持内联样式即style不推荐写内联样式但是内联样式的优先级最高若是内联样式与class定义了同样的属性不同的值肯定是内联生效。前面学了内联表达式和方法表达式其实定义是类似的内联表达式是直接将表达式写在了使用的地方而不是通过方法进行管理。这里的style也是内联样式。特别注意的是style本来支持的就是直接写样式不过vue中可以将font-size这种属性写成fontSize这么写是合法的。
对象绑定 这里的对象绑定写法和class类似不同的是class中对象绑定的key是css中的类名value是true或者false。style中的对象绑定key是css的原始的样式声明value是属性真正的值或者data变量。scriptexport default{data(){return{colorD:blue,font:40px}}}
/script
templateh1style绑定/h1p :style{color:colorD,fontSize:font}对象绑定/p
/template对象绑定除了上面的内联的写法外还可以写在data里scriptexport default{data(){return{colorD:blue,font:40px,styleObject:{color:blue,fontSize:40px}}}}
/script
templateh1style绑定/h1p :style{color:colorD,fontSize:font}对象绑定-内联/pp :stylestyleObject对象绑定-非内联/p
/template数组绑定 数组绑定中传的数组元素也必须是对象所以在使用style时感觉么有必要使用数组绑定对象绑定完全够用的如下所示scriptexport default{data(){return{colorD:blue,font:40px,styleObject:{color:blue,fontSize:40px}}}}
/script
templateh1style绑定/h1p :style{color:colorD,fontSize:font}对象绑定-内联/pp :stylestyleObject对象绑定-非内联/pP v-bind:style[styleObject]数组绑定/P
/template数组绑定还可以这么写scriptexport default{data(){return{colorD:blue,font:70px,styleObject:{color:blue,fontSize:40px}}}}
/script
templateh1style绑定/h1p :style{color:colorD,fontSize:font}对象绑定-内联/pp :stylestyleObject对象绑定-非内联/pP v-bind:style[styleObject]数组绑定/PP v-bind:style[styleObject,{fontSize:font}]数组绑定嵌套对象/P
/template小小总结style绑定直接写对象绑定即可对象中的属性名是各种样式value是样式的具体值这里推荐使用data里面声明对象不是直接卸载v-bind:style中class绑定感觉数组更好用里面可以传对象也可以传普通的单值这里的key都是class的类名value都是true或者false
2.13 侦听器
侦听器类似于java里的listener都能监控到数值的变化当数值变化时就会调用对应的监听方法。 代码如下
scriptexport default{data(){return{month:january}},methods:{changeMonth(){this.monthfebruary}},watch:{month(newValue,oldValue){alert(新值newValue, 老值oldValue)} }}
/script
templateh1测试侦听器/h1button click.stopchangeMonth()点击/buttonp{{ month }}/p
/template那侦听器都能监控哪些信息的变化呢
响应式数据变化这是最常见的数据也就是我们在data中声明的数据监听路由变化监听对象属性监听数组等 注意点监听响应式数据时监听器中的对应方法名必须数数据名称一致不然不生效若是监听器中只传入一个参数则传入的是新值传入两个参数则默认第一个是新值第二个是老值 小小总结 到现在已经学习了export下面的四个主要不分了datadata方法用以声明响应式数据methodsmethods对象用以声明函数computedcomputed对象用以声明计算属性结构和methods类似不过性能更好watchwatch对象用以声明监听的响应式数据等结构和methods类似入参是newValueoldValue
2.14 表单输入绑定双向绑定
这里叫双向绑定感觉更合适这种技术之前在angular时被认为是一个亮点后来的js框架基本都具备这个能力VUE自然也不会例外我们使用v-model将响应式数据绑定到输入框即可下面是测试代码
scriptexport default{data(){return{message:}},// 这块代码和这个功能没有关系只是顺手多写下作为巩固watch:{message(val){alert(监听到了变化val);}},// 这个方法是为了验证message数据变更会不会反向输出到inputmethods:{changeMsg(){this.messageaaa;}}}
/script
templateh1测试双向绑定/h1forminput typetext v-modelmessage/p{{ message }}/pbutton click.stopchangeMsg()点击更改/button/form
/template当在输入框输入数据时message信息也会在下方的p标签内展示反向测试的话点击点击更改按钮也会把信息进行更改也会体现在input上。 不过需要注意的是v-model支持了三种事件用来简化数据绑定的后续操作
lazy不做数据的实时变更到绑定的属性上只有提交等才会将变化体现出来测试时是失去光标触发了forminput typetext v-model.lazymessage/p{{ message }}/pbutton click.stopchangeMsg()点击更改/button
/formnumber将输入框的数据转为数值类型不过只有当输入框的type为number时才会生效其他类型的输入框即使用v-model.number也不会生效。 forminput typetext v-model.lazymessage/input typenumber v-model.numbermessage/p{{ message }}/pbutton click.stopchangeMsg()点击更改/button/formtrim去除输入框中字符串前后的空格中间空格无法去除forminput typetext v-model.lazymessage/input typenumber v-model.numbermessage/input typetext v-model.trimmessage/p{{ message }}/pbutton click.stopchangeMsg()点击更改/button
/form2.15 模板引用获取DOM树
原始的JS中是支持的获取DOM操作的上面的VUE已经提供了丰富的功能用来简化这一操作比如使用v-bind来简化属性绑定使用v-on来简化事件处理使用v-model简化数据绑定使用v-for简化列表的遍历。等vue提供了丰富的支持DOM的操作不过同时VUE也提供了特殊情况下对DOM的直接操作。分为两步即可直接操作DOM
1.需要获取到的标签上声明ref2.方法内部使用this.$refs获取dom然后就可以操作了
scriptexport default{data(){return {}},methods:{getDom(){// 注意这里的inpuDom是在input框中的ref的值console.log(this.$refs.inputDom);alert(this.$refs.inputDom);}}}
/script
templateh1测试获取DOM/h1input typetext refinputDom/button clickgetDom()点击获取DOM内容/button
/template三、组件
vue结尾的文件就是一个个组件组件是可以复用的需要时导入到对应场景即可。vue中有且一个根组件叫App.vue其他组件声明在component下面。
1 组件组成
下面是组件的标准组成有这三部分scriptstyletemplate。只有template是不可省略的其他均可省略。 style上的scoped表示样式只在当前组件内生效被嵌套到其他组件时不生效。
script
/script
style scoped
/style
template/template局部嵌套只需要两步即可
前提script 需要携带setup增加setup相当于增加默认导出
1.引入组件在script中使用 import 组件名 from ./components/组件名.vue
2.显示组件在template中引入组件组件名/
3.如果没有前提需要在script增加组件导入
export default{components:{CatchDom:CatchDom}
}2 组件嵌套关系
组件之间支持相互嵌套有很多组件是共用的比如头部的左侧的菜单栏等在真实项目中都是共用的所以组件嵌套是很有必要的类似下图 组件嵌套就是引入组件即可不同组件定义好自己的边界即可。
3 组件注册方式
上面在组件组成中说了局部注册这里说下全局注册全局注册只需要在main.js中注册一次然后就可以在所有的文件中进行直接在template中使用了很省事但对于VUE项目来说打包时无论全局引入的组件是否真的被使用都会被打包带走这点算是全局注册的弊端同时全局注册会造成组件间的关系不够清晰这是官方话我感觉听清晰的。 看全局引入前线看下main.js的代码
// 使用 ES6 的模块导入语法从 vue 模块中导入 createApp 函数。
// createApp 函数是 Vue 3 中用于创建 Vue 应用实例的工厂函数。
import { createApp } from vue
// 导入名为 App 的组件该组件位于当前文件所在目录下的 App.vue 文件中。
// 这里假设 App.vue 是根组件它将被挂载到 DOM 中。
import App from ./App.vue
// 调用 createApp 函数传入 App 组件作为参数创建一个 Vue 应用实例。
// 这个实例将用于管理组件的生命周期、状态和渲染等。
// 使用 mount 方法将 Vue 应用实例挂载到指定的 DOM 元素上。
// 这里的 #app 是一个选择器表示选择 id 为 app 的元素作为挂载目标。
createApp(App).mount(#app)mian.js 中就三行代码但是这三行代码很重要没有他项目根本跑不起来第一行是从vue中导入createApp函数第二行导入App.vue这个组件第三行是先用createApp根据导入的App组件创建出一个App然后调用App的mout函数将App挂载到DOM上这里的DOM在index.html中。 言归正传怎么做全局导入呢如下只需两步
1.导入组件import CatchDom from ./components/CatchDom.vue;
2.将组件加入到app createApp(App).component(CatchDom,CatchDom).mount(#app)然后需要在哪里使用就在哪里的template中引入即可这里就和setup没有关系了有没有都不影响引入了
4 组件传递数据 props
既然项目中一个页面是由多个组件共同构成的那就免不了需要相互之间传递和共享参数所以props绝对是重点中的重点了虽然重点但是很简单。 假设有着这样的场景App这个根组件中引入了one组件one组件中引入了two组件想要将one组件的数据传入到two组件中。 下面是one组件的代码
templateh1one/h1two msg我是one里面的参数/
/template下面是two组件的代码
scriptexport default{props:[msg]}
/script
templateh1two/h1p{{ msg }}/p
/template下面是展示效果 可以看到one里面的信息被传入到了two中这样就实现了组件间的数据传递 1.父组件传递参数时参数写在template中引入的子组件中 2.子组件接收参数时必须使用props接收写法固定props:[“参数”] 3.子组件接收的参数相当于自己在data中声明的响应式数据一样可以使用{{}}进行获取 4.父组件若是想要动态传参只需要为参数增加v-bind:参数“文本插值”这里很有意思v-bind绑定的数据并不是这正的html属性而是我们想要传递的参数这个值可以是任何非关键字的信息
另外展示下动态传参相对于上面的静态传参的例子只需改动one组件内容如下即可
script
export default{data(){return{msg:我是one里面的参数-动态}}
}
/script
templateh1one/h1two v-bind:msgmsg/
/template5 组件传递多种数据类型类型校验参数默认值
多种参数类型的传递与基本参数没有啥区别就是将我们在data区域渲染的数据进行传递传递以后的数据依然支持使用{{}}进行获取。我们可以想到的数据类型都是支持传递的。
这是父组件信息
script
import sonOne from ./sonOne.vue
export default{data(){return{msg:[12,122]}},components:{sonOne:sonOne}
}
/script
templateh1父组件信息/h1sonOne :msgmsg/
/template这是子组件信息
scriptexport default{props:[msg]}
/script
templateh1子组件信息/h1p{{ msg }}/p
/template5.1 类型校验
若是需要对参数校验则需要改变之前使用props写的接收参数方式需要更改为使用对象来接收父组件传递的参数对象内部声明各个接收的参数为对象为每个对象增加type属性。 单类型校验:需要注意的是若是校验不满足不会影响运行单console会有警告提示
props:{msg:{type:String,}
} 多类型校验后跟数组满足其中任何一种类型均不会有警告发生
props:{msg:{type:[String,Number,Array,Object]}
}
5.2 组件传参默认值
上面已经说了类型校验当子组件接收不到父组件信息时一般是需要一个默认值的这个默认值可以避免出现undefined或者不展示的问题。代码如下 数字和字符串直接声明默认值即可但是对象和数组则需要通过方法来进行声明默认值:
父组件传递参数均没有区别这里不展示
props:{msg:{// type:Objecttype:[String,Number,Array,Object]},age:{type:Number,default:0},month:{type:Array,default(){return [kong]}},customer:{type:Object,default(){return{age:0,name:空,sex:男}}}}5.3 声明必填
前面说了类型校验、默认值声明子组件还支持对是否必传进行校验使用required进行校验当为true时若是没有传该值则在console上给出警告
props:{month:{type:Array,required:true,default(){return [kong]}}
}7 组件事件和v-model
这里的组件事件就是自定义事件所谓自定义事件就是支持子组件将信息传递给父组件。也就是在子组件中声明自定义事件名在父组件中定义事件的执行这就是组件事件。前面已经有了父传子的方法使用props子传父就是使用组件事件了这样无论组件怎么调用都可以实现参数的传递了。 下面是子组件的代码
script
export default{data(){return{msg:这是子组件信息}},watch:{msg(newValue){// alert(触发了)this.$emit(myEvent,newValue)}}
}
/script
templateh1组件Two/h1input typetext v-modelmsg/
/template下面是父组件的代码
script
import ComponentTwo from ./ComponentTwo.vue
export default{components:{ComponentTwo:ComponentTwo},methods:{fatherFun(data){this.faMsgdata}},data(){return{faMsg:}}
}
/script
template
h1组件One/h1
input typetext :valuefaMsg/
ComponentTwo myEventfatherFun/
/template注意事项
子组件可以不使用v-model用其他事件触发$emit 也是一样的比如单机事件等子组件调用父组件的自定义事件必须使用$emit 如果只传一个参数默认是父组件的自定义事件名若是两个参数则第二个参数是传递的数据父组件中自定义事件必须定义在引入 组件的地方声明方式可以使用v-on或者这点与VUE的事件写法没有区别父组件中自定义事件写在引入的子组件时只能写在这里绝对不能写参数这里直接写名称即可也不能带括号如ComponentTwo myEvent“fatherFun”/自定义事件声明在methods对象中与普通方法无异若是有参数需要在这里进行声明才可以使用如myEvent(data){}
8 组件事件配合v-model和watch实现父子组件数据的实时互传
上面的例子已经介绍了有v-model的使用他的作用其实就是方便数据可以实时被变更。因为他的作用本来就是双向绑定的他实时变更了就可以使用watch对他进行侦听这样就方便数据回传父组件了。不使用这种方式单独加个单击事件当事件触发时回传父组件也是一样的。前面已经有了父传子和子传父这里介绍下如何使用$emitv-modelwatch实现父子组件数据的实时互传。 这是子组件代码
script
export default{data(){return{msg:这是子组件信息}},watch:{msg(newValue){this.$emit(myEvent,newValue)},data(){this.msgthis.data;}},props:{data:{type:String,default:空,required:true}}
}
/script
templateh1组件Two/h1input typetext v-modelmsg/
/template这是父组件代码
script
import ComponentTwo from ./ComponentTwo.vue
export default{components:{ComponentTwo:ComponentTwo},methods:{fatherFun(data){this.faMsgdata}},data(){return{faMsg:,faMsg2:}},watch:{faMsg(){// alert(触发了)this.faMsg2 this.faMsg;}}
}
/script
template
h1组件One/h1
input typetext v-modelfaMsg/
ComponentTwo v-on:myEventfatherFun :datafaMsg2/
/template以上思路以上代码更改完没有立即生效隔了几分钟才生效不知原因 1.子组件定义参数msg页面使用v-model进行展示这样数据实时的变化就会回传给msg了 2.子组建中定义msg的侦听方法当msg变动时用$emit 将msg信息传递给父组件 3.父组件使用自定义事件fatherFun接收传递的msg将其给到自定义的参数faMsg然后进行了展示这里使用v-model绑定faMsg 4.父组件自定义参数faMsg2给faMsg提供侦听方法当异动时将faMsg 赋值给faMsg2 5.将faMsg2传递给子组件父组件传递子组件属于实时传递这里类似于侦听变化当值发生变动就会自动传递到子组件这是VUE定义好的动作 6.子组件在props中使用data接收传递的参数faMsg2 7.为data提供侦听方法当data变动时实现将data的值赋给第一步的msg。到此就实现了父子组件单个参数的实时传递 这是是根据之前所学自己琢磨的感觉这个步骤还可以简化下在父组件中若是不增加额外的变量直接建faMsg回传给子组件不知道是否可行 经验证可行父组件代码可直接简化为如下
script
import ComponentTwo from ./ComponentTwo.vue
export default{components:{ComponentTwo:ComponentTwo},methods:{fatherFun(data){this.faMsgdata}},data(){return{faMsg:}}
}
/script
template
h1组件One/h1
input typetext v-modelfaMsg/
ComponentTwo v-on:myEventfatherFun :datafaMsg/
/template可以这么改的核心是faMsg必须使用v-model进行绑定不然他的变化没有实时体现到变量faMsg上这样组父组件就不会实时传递到子组件了这个是关键点
9 组件数据传递使用props进行子传父
前面说props只能由父传递到子组件也不错因为当我们传递到子组建的不是数据而是函数的时候这时候子组件接收到函数就可以使用使用时传入的参数真正调用的点还是在父组件所以父组件还是可以拿到这个参数的这个和java里的函数调用没啥区别这是垮了类而已。 感想包括声明的scoped 有点和private类似import 和java的import也是类似使用时java里需要再次进行操作vue中也是需要我们再操作一次不过感觉使用components有些多余了下面是如何利用props传递方法实现子传父的不过这种方式无法实现既携带方法又携带数据若是想要传递数据还需要写别的props感觉也没有多大优势。 下面是子组件代码
script
export default{props:{doTrunser:{type:Function,required:true}}
}
/script
templateh1ParentSon组件/h1button clickdoTrunser(李四)点击触发/button
/template下面是父组件代码
script
import ParentSon from ./ParentSon.vue
export default{data(){return{msg:张三}},methods:{trunser(data){this.msgdata;}},components:{ParentSon:ParentSon}
}
/script
templateh1Parent组件/h1p{{ msg }}/pParentSon :doTrunsertrunser/
/template感觉还是使用props传递普通参数实现父传子使用$emit来实现子传父更好些也更好实现父子间数据的实时传递
10 透传attributes
一个基本没有用的知识点当在引入的子组件上声明class样式时就是原始的class样式若是子组件只有一个根标签则跟标签会继承这个属性若是想要禁止这种属性集成可以如下进行操作声明为false则取消自动继承。
11 插槽slots
开发VUE项目时需要定义很多的组件方便我们复用但是各个组件若是定义的弹窗或者响应格式不统一怎么办到时候项目就会很难看。为了解决这个问题VUE还支持了插槽。当我们在父组件中引入了各个子组件时此时预留一部分功能由父组件实现所有子组件只做一个接口留给父组件进行真正的操作这就是插槽有点类似于java里的接口对于插槽子组件 只定义在哪里使用真正怎么展示和内部逻辑是什么样这个由父组件决定。插槽和组件的引入共同构成了项目的可拆卸的灵活性。 下面展示插槽的基础用法的父组件代码
script
import ComponentB from ./ComponentB.vue
export default{components:{ComponentB:ComponentB},data(){return{message:测试传参可好使}}
}
/script
templateh1ComponentA组件/h1ComponentB :msgmessagetemplate v-slot:slotAh1插槽A/h1/templatetemplate v-slot:slotBh1插槽B/h1/template/ComponentB
/template下面是子组件代码
script
export default{data(){return{}},props:{msg:{type:String,default:空,required:true}}
}
/script
templateh1ComponentB组件/h1slot nameslotAa href #这是默认内容/a/slotp{{ msg }}/pslot nameslotBa href #这是默认内容/a/slot
/template
定义插槽时引入的子组件标签必须是双标签不可以单标签引入插槽时引入的组件标签同样支持数据的传递和自定义事件的回传他和单标签引入子组件是没有区别的若是需要声明多个插槽需要使用不同的模板template在不同的模板内声明v-slot:插槽名来对不同的插槽进行声明注意插槽名前面是冒号不是等于插槽名也无需加引号这就是具名插槽v-slot可省略为#插槽内的值同样可以是data中渲染的数据使用和普通的模板没有区别插槽使用时只需要slot标签就可以若是父组件声明了多个插槽则需要声明插槽的名称使用name来声明不同的插槽的名称插槽是双标签slot他的内部支持声明插槽的默认内容当父标签未声明插槽或者声明的插槽未找到时将使用默认的样式。插槽使用的数据需要在父组件中进行渲染这里感觉放父组件也没有问题不过使用插槽一般数据肯定在子组件到时候还是需要$emit登场来解决参数传递的问题往后看了下发现VUE提供了插槽传参的方式专用于将子组件信息通过插槽传递到父组件这就实现了父子组件数据互传了
下面是使用插槽实现子传父时的子组件代码
script
export default{data(){return{msg22:我是子组件内容1,day:我是子组件内容2}},props:{msg:{type:String,default:空,required:true}}
}
/script
templateh1ComponentB组件/h1slot nameslotA :msgmsg22a href #这是默认内容/a/slotp{{ msg }}/pslot nameslotB :daydaya href #这是默认内容/a/slot
/template下面是父组件代码
script
import ComponentB from ./ComponentB.vue
export default{components:{ComponentB:ComponentB},data(){return{message:测试传参可好使}}
}
/script
templateh1ComponentA组件/h1ComponentB :msgmessagetemplate v-slot:slotAslotPropsh1{{ slotProps.msg }}/h1/templatetemplate #slotBslotPropsh1{{ slotProps.day }}/h1/template/ComponentB
/template子组件中进行属性绑定传值这点与父组件传递值时是相同的父组件接收子组件传递的信息时必须在插槽名后声明slotProps slotProps是子组件插槽属性的对象他的内部涵盖了子组件声明的所有属性每个插槽都拥有一个slotProps但是不同的插槽不可共用不可跨插槽使用同一个插槽内可声明多个数据进行传递获取数据时slotProps对象直接点对应属性就可以获取到我们从子组件传递到插槽内的值了父组件中集成了子组件的信息后还会再回传子组件。这就实现了父子组件通过插槽进行信息互传了
12 组件生命周期
描述的是组件从创建到销毁的全过程在这个过程中VUE会执行很多方法来对组件作不同的操作在这个过程中VUE会运行一些组件生命周期钩子函数这些函数会在组件生命周期的特定阶段进行触发因此程序员得以通过这些方法对组件的不同生命周期进行干预和操作。这个有点类似于Spring中Bean的生命周期在Bean的生命周期中我们可以定义init和destroy以及实现一些handler接口和processor接口来进行不同的动作。这个设计思想都是类似的。 上面是老图下面是新图 可以看到destroy阶段改为了取消挂载对应的方法也改成了取消挂载前和取消挂载后 一般将组件的生命周期分为四个阶段每个阶段都有前置和后置方法调用创建阶段、挂载阶段、更新阶段、销毁阶段。每个阶段都有一个操作前和操作后的方法共8个钩子函数。分别如下
生命周期描述beforeCreate组件实例被创建之初created组件实例已经完全创建beforeMount组件挂载之前mounteds组件挂载到实例上去之后beforeUpdate组件数据发生变化更新之前updated数据数据更新之后beforeUnmount组件取消挂载之前unMounted组件取消挂载之后activatedkeep-alive 缓存的组件激活时deactivatedkeep-alive 缓存的组件停用时调用errorCaptured捕获一个来自子孙组件的错误时被调用这些方法在特定时期都是会被自动触发的那这些方法应该写在哪里怎么写呢答案是都写在export default中即可作为和data方法平级的方法就行VUE在相应阶段就会自动调用
script
export default{data(){return{message:测试数据更新,customer:[]}},methods:{change(){this.message 我更新了}},beforeCreate(){console.log(创建前);},created(){console.log(创建后);},beforeMount(){console.log(挂载前:this.$refs.buttonRef);this.customer [张三,李四,王五]},mounted(){console.log(挂载后:this.$refs.buttonRef);},beforeUpdate(){console.log(更新前);},updated(){console.log(更新后);},beforeUnmount(){console.log(销毁前);},unmounted(){console.log(销毁后);}
}
/script
templateh1测试组件的生命周期/h1p refbuttonRef{{ message }}/pbutton clickchange()单击更新/buttonulli v-for(cus,index) in customer :keyindex{{ cus }}/li/ul
/template上面的代码还包含了两个验证
在mounted方法增加了对数组customer的数据初始化这里正常是可以去做网络请求的因为dom已经渲染结束了。打开页面可以看到数据已经正常出来了说明没问题点击更新按钮更新了message这个变量的值理论上会触发beforeUpdate、updated两个方法 总结 初始化初始化一个空的VUE实例对象此时只有空的钩子函数和事件其他都不存在1.创建阶段初始化data、methods等内容这个阶段是解析VUE原始信息 间隙在创建和挂载的间隙VUE会对模板进行编辑根据之前的data、methods等数据这里会编译成一个模板字符串然后将其渲染为内容中的DOM2.挂载阶段之前已经解析出了VUE的信息并放在了内存这个阶段将内存中的DOM替换到页面中 间隙数据发生改变数据响应到了data中data中的数据为最新数据3.更新阶段根据data中的数据在内存中从新渲染出一份新的DOM然后将DOM信息更新到页面中 间隙准备取消挂载此时组件功能一切可用4.将组件信息从挂载处取消 感觉生命周期还是很有用的完全可以在mounted阶段去将网络请求提前做好这样就做到了数据的提前加载降低了数据渲染所需要的时间。
15 动态组件
可以根据条件动态更换展示哪个组件这种感觉工作中肯定也会碰到的代码如下
script
import ComponentA from ./components/ComponentA.vue
import LifeCycle from ./components/LifeCycle.vue;
export default{components:{ComponentA,LifeCycle},data(){return{showComponet:ComponentA}},methods:{changeComponent(){this.showComponet this.showComponetComponentA?LifeCycle:ComponentA}}
}
/script
templatebutton clickchangeComponent更换组件/buttoncomponent :isshowComponet/component/template总结
1.在需要引入多个组件的组件内的模板内使用component标签这是一个双标签2.为component标签声明一个v-bind:is“” ,这里声明使用哪个组件即可这个组件可以是data中渲染的数据这样就可以做成动态了3.若是动态的无论是声明初始值还是后来的更改值组件名必须加引号也就是字符串4.被切换掉的组件会触发beforeunMount 和 unMounted方法
16 组件保持存活keep-alive/KeepAlive
组件保持存活用起来很简单直接在component外面加上keep-alive标签即可该标签可以让组件被卸载时不被真正卸载而是进入缓存同时组件的数据也会被缓存当组件切换回来时数据还是之前的数据
script
import ComponentA from ./components/ComponentA.vue
import LifeCycle from ./components/LifeCycle.vue;
export default{components:{ComponentA,LifeCycle},data(){return{showComponet:ComponentA}},methods:{changeComponent(){this.showComponet this.showComponetComponentA?LifeCycle:ComponentA}}
}
/script
templatebutton clickchangeComponent更换组件/buttonKeepAlivecomponent :isshowComponet/component/KeepAlive
/template1.使用很简单直接使用KeepAlive或者keep-alive标签均可以2.使用该标签会缓存组件和数据切换回来后数据使用的是缓存数据不是默认数据
17 异步组件
这里的异步组件和java里的异步不是一个概念这里的异步更像是懒加载按照懒加载理解基本无误默认情况VUE会在创建阶段加载全部的组件然后在挂载阶段去对响应的组件进行挂载。使用异步组件后组件的初始化和挂载会被迁移到需要的时候才处理怎么感觉都是懒加载这就是前端的异步的概念突出一个不非阻塞的返回。 下面是异步组件的用法
从VUE中引入defineAsyncComponentimport { defineAsyncComponent } from ‘vue’;使用defineAsyncComponent加载组件使用该方法加载的组件就是异步组件了声明的是组件名和import 组件名 from 的组件名没有区别
const LifeCycle defineAsyncComponent(()import(./components/LifeCycle.vue)
)异步组件的显著特点是只有调用才会对组件进行初始化和挂载
18 依赖注入
这里的依赖注入和java里的依赖注入有点类似可以类比同样的关键字inject。只需要在爷爷组件中在export中使用provide进行数据暴露即可这个操作类似往池子中扔了一个数据inject就可以从这个池子中获取这个数据了。 下面是爷爷组件信息
script
import { defineAsyncComponent } from vue;
import ComponentA from ./components/ComponentA.vue
// import LifeCycle from ./components/LifeCycle.vue;
const LifeCycle defineAsyncComponent(()import(./components/LifeCycle.vue)
)
export default{components:{ComponentA,LifeCycle},data(){return{showComponet:ComponentA,injectMsg:我是爷爷组件的数据}},methods:{changeComponent(){this.showComponet this.showComponetComponentA?LifeCycle:ComponentA}},provide(){return{inMsg:this.injectMsg}}
}
/script
templatebutton clickchangeComponent更换组件/buttonKeepAlivecomponent :isshowComponet/component/KeepAlive
/template下面是孙子组件代码 孙子接收时的写法既可以使用数组来直接接收也可以和props写法保持一致对类型、默认值、是否必须等进行限定
script
export default{data(){return{msg22:我是子组件内容1,day:我是子组件内容2}},props:{msg:{type:String,default:空,required:true}},inject:{inMsg:{type:String,default:我是爷爷组件的数据的默认值}}
}
/script
templateh1ComponentB组件/h1slot nameslotA :msgmsg22a href #这是默认内容/a/slotp{{ msg }}/pslot nameslotB :daydaya href #这是默认内容/a/slotp{{ inMsg }}/p
/template 总结组件数据交互方式
props父传子正常传递子传父可借助函数$emit: 通过自定义函数实现子传父slot: 利用插槽的slogProps 属性对象来实现子传父插槽本身就是父传子不过传递的是DOM信息provide/inject: 依赖注入实现父传子/孙子等实现跨组件传递数据爷爷组件通过provide提供数据孙子组件通过inject获取数据 文章转载自: http://www.morning.qbfwb.cn.gov.cn.qbfwb.cn http://www.morning.pbwcq.cn.gov.cn.pbwcq.cn http://www.morning.dysgr.cn.gov.cn.dysgr.cn http://www.morning.fktlr.cn.gov.cn.fktlr.cn http://www.morning.qcdtzk.cn.gov.cn.qcdtzk.cn http://www.morning.rgqnt.cn.gov.cn.rgqnt.cn http://www.morning.fycjx.cn.gov.cn.fycjx.cn http://www.morning.mlgsc.com.gov.cn.mlgsc.com http://www.morning.clccg.cn.gov.cn.clccg.cn http://www.morning.bmlcy.cn.gov.cn.bmlcy.cn http://www.morning.jykzy.cn.gov.cn.jykzy.cn http://www.morning.rfxw.cn.gov.cn.rfxw.cn http://www.morning.dfrenti.com.gov.cn.dfrenti.com http://www.morning.nqyfm.cn.gov.cn.nqyfm.cn http://www.morning.ftlgy.cn.gov.cn.ftlgy.cn http://www.morning.tnbas.com.gov.cn.tnbas.com http://www.morning.kwksj.cn.gov.cn.kwksj.cn http://www.morning.jfgmx.cn.gov.cn.jfgmx.cn http://www.morning.lsyk.cn.gov.cn.lsyk.cn http://www.morning.lfmwt.cn.gov.cn.lfmwt.cn http://www.morning.xq3nk42mvv.cn.gov.cn.xq3nk42mvv.cn http://www.morning.bpyps.cn.gov.cn.bpyps.cn http://www.morning.tknqr.cn.gov.cn.tknqr.cn http://www.morning.plwfx.cn.gov.cn.plwfx.cn http://www.morning.ygkq.cn.gov.cn.ygkq.cn http://www.morning.hxwhyjh.com.gov.cn.hxwhyjh.com http://www.morning.mqxzh.cn.gov.cn.mqxzh.cn http://www.morning.xfjwm.cn.gov.cn.xfjwm.cn http://www.morning.srbl.cn.gov.cn.srbl.cn http://www.morning.ljpqy.cn.gov.cn.ljpqy.cn http://www.morning.znpyw.cn.gov.cn.znpyw.cn http://www.morning.pkrb.cn.gov.cn.pkrb.cn http://www.morning.ckhyj.cn.gov.cn.ckhyj.cn http://www.morning.ybshj.cn.gov.cn.ybshj.cn http://www.morning.zdydj.cn.gov.cn.zdydj.cn http://www.morning.jtrqn.cn.gov.cn.jtrqn.cn http://www.morning.dbqcw.com.gov.cn.dbqcw.com http://www.morning.ylpl.cn.gov.cn.ylpl.cn http://www.morning.pnmgr.cn.gov.cn.pnmgr.cn http://www.morning.hgtr.cn.gov.cn.hgtr.cn http://www.morning.ptmgq.cn.gov.cn.ptmgq.cn http://www.morning.rhmt.cn.gov.cn.rhmt.cn http://www.morning.ydyjf.cn.gov.cn.ydyjf.cn http://www.morning.kndst.cn.gov.cn.kndst.cn http://www.morning.dsmwy.cn.gov.cn.dsmwy.cn http://www.morning.wrtbx.cn.gov.cn.wrtbx.cn http://www.morning.xcbnc.cn.gov.cn.xcbnc.cn http://www.morning.fnfxp.cn.gov.cn.fnfxp.cn http://www.morning.kpypy.cn.gov.cn.kpypy.cn http://www.morning.hqllx.cn.gov.cn.hqllx.cn http://www.morning.gmmyn.cn.gov.cn.gmmyn.cn http://www.morning.geledi.com.gov.cn.geledi.com http://www.morning.hnhgb.cn.gov.cn.hnhgb.cn http://www.morning.ktrh.cn.gov.cn.ktrh.cn http://www.morning.srgyj.cn.gov.cn.srgyj.cn http://www.morning.bpmnh.cn.gov.cn.bpmnh.cn http://www.morning.jngdh.cn.gov.cn.jngdh.cn http://www.morning.nbhft.cn.gov.cn.nbhft.cn http://www.morning.c7617.cn.gov.cn.c7617.cn http://www.morning.nrzbq.cn.gov.cn.nrzbq.cn http://www.morning.wwjft.cn.gov.cn.wwjft.cn http://www.morning.ldynr.cn.gov.cn.ldynr.cn http://www.morning.coffeedelsol.com.gov.cn.coffeedelsol.com http://www.morning.jjnql.cn.gov.cn.jjnql.cn http://www.morning.gkfwp.cn.gov.cn.gkfwp.cn http://www.morning.jwtjf.cn.gov.cn.jwtjf.cn http://www.morning.llcsd.cn.gov.cn.llcsd.cn http://www.morning.pjzcp.cn.gov.cn.pjzcp.cn http://www.morning.jyjqh.cn.gov.cn.jyjqh.cn http://www.morning.sfwd.cn.gov.cn.sfwd.cn http://www.morning.nicetj.com.gov.cn.nicetj.com http://www.morning.cmqrg.cn.gov.cn.cmqrg.cn http://www.morning.mfzyn.cn.gov.cn.mfzyn.cn http://www.morning.qtzwh.cn.gov.cn.qtzwh.cn http://www.morning.qmrsf.cn.gov.cn.qmrsf.cn http://www.morning.rrrrsr.com.gov.cn.rrrrsr.com http://www.morning.lzrpy.cn.gov.cn.lzrpy.cn http://www.morning.srzhm.cn.gov.cn.srzhm.cn http://www.morning.rdbj.cn.gov.cn.rdbj.cn http://www.morning.rfgkf.cn.gov.cn.rfgkf.cn