网站建设 微信开发 h5开发,网站建设是 口号,c 能用来做网站,安徽省工程信息网官网文章目录 第 1 章#xff1a;Vue 核心1、 Vue 简介1.官网2.介绍与描述3. Vue 的特点4. 与其它 JS 框架的关联5. Vue 周边库 2、初始Vue3、模板语法1、Vue模板语法有2大类:2、插值语法和指令语法 4、数据绑定1. 单向数据绑定2. 双向数据绑定 5、el与data的两种写法1.e1有2种写法… 文章目录 第 1 章Vue 核心1、 Vue 简介1.官网2.介绍与描述3. Vue 的特点4. 与其它 JS 框架的关联5. Vue 周边库 2、初始Vue3、模板语法1、Vue模板语法有2大类:2、插值语法和指令语法 4、数据绑定1. 单向数据绑定2. 双向数据绑定 5、el与data的两种写法1.e1有2种写法2.data有2种写法3.一个重要的原则: 6、 MVVM 模型7、数据代理1、 Object.defineProperty方法2、数据代理1、概念2、Vue中的数据代理:3、Vue中数据代理的好处:4、基本原理: 8、事件处理1、事件的基本使用:2、事件修饰符3、键盘事件 9、计算属性与监视1、计算属性 computed2、监视属性1、监视属性 watch及简写方式:1、深度监听 deep 3、计算属性computed和监听属性watch的对比 10、class 与style的绑定11、条件渲染1.V-if2.V-show3.备注: 12、列表渲染v-for指令1、遍历列表时key的作用index作为key2、遍历列表时key的作用id作为key3、面试题: react、vue中的key有什么作用? (key的内部原理) 13、列表过滤14、列表排序15、vue检测数据的原理16、收集表单数据17、过滤器18、内置指令与自定义指令1、常用内置指令 19、自定义指令1、自定义指令总结:2、自定义指令案例函数式及对象式 20、生命周期1、vm的生命周期2、常用的生命周期钩子:3、关于销毁Vue实例常用指令总结 第 2 章Vue 组件化编程1、 模块与组件、模块化与组件化1. 模块2. 组件3. 模块化4. 组件化 2、非单文件组件1、概念 3、Vue中使用组件的三大步骤:一、 如何定义一个组件二、如何注册组件?三、编写组件标签: 4、组件的几个注意事项1.关于组件名:2.关于组件标签:3.一个简写方式: 5、组件的嵌套6、关丁VueComponent:7、一个重要的内置关系:1.一个重要的内置关系:2.为什么要有这个关系: 8、单文件组件1. 一个.vue 文件的组成(3 个部分) 第 3 章使用 Vue 脚手架1 初始化脚手架1、说明2 、具体步骤第一步仅第一次执行全局安装vue/cli。第二步切换到你要创建项目的目录然后使用命令创建项目第三步启动项目备注 3 模板项目的结构4、关于不同版本的Vue: 2 ref 与 props1、ref2、props 3 混入minxin4 插件1、功能:2、本质:3、定义插件:4、再main.js中使用插件: 5、scoped样式6、组件的自定义事件7、全局事件总线 (GlobalEventBus)任意组件间通信8、消息订阅与发布1 理解2 使用 PubSubJS3、总结nextTick 9 、Vue封装的过度与动画 第 4 章Vue 中的 ajax1 解决开发环境 Ajax 跨域问题代理服务器2、vue脚手架配置代理3、插槽1.作用:2.分类:3.使用方式1、默认插槽2、具名插槽 3.作用域插槽:1.理解:2.具体编码 第 5 章vuex1、理解 vuex1 vuex 是什么 2、什么时候使用 Vuex3、搭建环境1、创建文件src/store/index.js2、在mian.js中创建vm时传入store配置项 4、基本使用1、初始化数据、配置actions、配置mutations操作文件store.js2、组件中读取vuex中的数据3.组件中修改vuex中的数据: 5、getters的使用1.概念:2.在store.js 中追加getters 配置3.组件中读取数据: 6、四个map方法的使用1.mapstate方法:2.mapGetters方法:3.mapActions方法:4.mapMutations方法: 7.模块化命名空间1.目的:2.修改store.js 第 6 章vue-router路由1 vue-router 的理解2 对 SPA 应用的理解3 路由的理解1. 什么是路由?2. 路由分类1. 后端路由2. 前端路由 4 路由的基本使用1.安装vue-router命令:2.应用插件:3.编写router配置项:4.实现切换(active-class可配置高亮样式)5.指定展示位置6.几个注意点 5、嵌套多级路由1.配置路由规则使用children配置项:2.跳转 (要写完整路径) : 6、路由的query传参1、传递参数2、接收参数 7、命名路1.作用:2.如何使用1.给路由命名2.简化跳转: 8、路由的params参数1、配置路由声明接收 params参数2、传递参数3、接收参数 9.路由的props配置10.router-link的replace属性11.编程式路由导航11、缓存路由组件12.两个新的生命周期钩子13、路由守卫1. 作用2. 分类3. 全局守卫:4. 独享守卫:5. 组件内守卫 14、路由器的两种工作模式 vue3快速上手一、创建Vue3.0工程1.使用 vue-cli 创建2.使用 vite 创建3.分析工程结构 二、常用 Composition API1.拉开序幕的setup2.ref函数3.reactive函数4.Vue3.0中的响应式原理vue2.x的响应式Vue3.0的响应式 5.reactive对比ref6.setup的两个注意点7.计算属性与监视1.computed函数2.watch函数3.watchEffect函数 8.生命周期9.自定义hook函数10.toRef 三、其它 Composition API1.shallowReactive 与 shallowRef2.readonly 与 shallowReadonly3.toRaw 与 markRaw4.customRef5.provide 与 inject6.响应式数据的判断 四、Composition API 的优势1.Options API 存在的问题.Composition API 的优势 五、新的组件1.Fragment2.Teleport3.Suspense 六、其他1.全局API的转移2.其他改变 第三方库浏览器本地存储 第 1 章Vue 核心
1、 Vue 简介
1.官网
英文官网: https://vuejs.org/中文官网: https://cn.vuejs.org/
2.介绍与描述
1、动态构建用户界面的渐进式 JavaScript 框架 构造用户界面将数据展示到用户可以看见的界面 渐进式vue可以自底向上逐层的应用 简单应用只需一个轻量小巧的核心库 复杂应用可以引入各式各样的vue插件 2、 作者: 尤雨溪
3. Vue 的特点
遵循 MVVM 模式编码简洁, 体积小, 运行效率高, 适合移动/PC 端开发它本身只关注 UI, 也可以引入其它第三方库开发项目采用组件化模式提高代码复用率、且让代码更好维护声明式编码让编码人员无需直接操作DOM,提高开发效率
4. 与其它 JS 框架的关联
借鉴 Angular 的模板和数据绑定技术借鉴 React 的组件化和虚拟 DOM 技术
5. Vue 周边库
vue-cli: vue 脚手架vue-resourceaxiosvue-router: 路由vuex: 状态管理element-ui: 基于 vue 的 UI 组件库(PC 端)等
2、初始Vue
1.想让Vue工作就必须创建一个Vue实例且要传入一个配置对象; 2.root容器里的代码依然符合htm1规范只不过混入了一些特殊的Vue语法; 3.root容器里的代码被称为[Vue模板]: 4.Vue实例和容器是一 一对应的; 5.真实开发中只有一个Vue实例并且会配合着组件一起使用; 6.{{xxx}}中的xxx要写js表达式且xxx可以自动读取到data中的所有属性; 7.一旦data中的数据发生改变那么模板中用到该数据的地方也会自动更新: 注意区分JS表达式和JS代码 1、表达式一个表达式会产成一个值可以放在任何一个需要值的地方如ab 等 2、JS代码如for循环if语句
!DOCTYPE html
html langen
headmeta charsetUTF-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0titleDocument/titlescript typetext/javascript src../js/vue.js/script/head
bodydiv idrooth1插值语法/h1h1你好我是{{name}}/h1/divscript typetext/javascript//阻止vue 在启动时生成生产提示Vue.config.productionTipfalse//创建Vue实例new Vue({el:#root,//el用于指定当前vue实例为那个容器服务值通常为css选择器字符串data:{ //data中用来存储数据数据供el所指定的容器去使用值我们暂时先写成一个对象name:vue}})/script
/body
/html3、模板语法
1、Vue模板语法有2大类:
1.插值语法: 功能:用于解析标签体内容。双标签中间的内容 写法: {{xxx}}xxx是js表达式且可以直接读取到data中的所有属性。 2.指令语法: 功能:用于解析标签(包括: 标签属性、标签体内容、绑定事件…) 举例:v-bind:hrefxxx”或 简写为 :href“xxx”xxx同样要写js表达式且可以直接读取到data中的所有属性。 备注:Vue中有很多的指令且形式都是: v-???此处我们只是拿v-bind举个例子。
2、插值语法和指令语法
bodydiv idrooth1插值语法/h1h2Hello{{name}}/h2h1指令语法/h1!-- 原始写法 --a v-bind:hrefschool.url点击我去{{school.name}}/aa :hrefschool.url/a/divscript typetext/javascript//阻止vue 在启动时生成生产提示Vue.config.productionTipfalse//创建Vue实例new Vue({el:#root,//el用于指定当前vue实例为那个容器服务值通常为css选择器字符串data:{ //data中用来存储数据数据供el所指定的容器去使用值我们暂时先写成一个对象name:vue,school:{name:学习,url:https:www.baidu.com}}})/script
/body4、数据绑定
1. 单向数据绑定
语法v-bind:href “xxx” 或简写为 :href特点数据只能从 data 流向页面
2. 双向数据绑定
语法v-mode:value“xxx” 或简写为 v-model“xxx”特点数据不仅能从 data 流向页面还能从页面流向data 备注: 1.双向绑定一般都应用在表单类元素上 (如: input、select等) 2.v-model:value 可以简写为 v-model因为v-model默认收集的就是value值. 如
bodydiv idroot!-- 普通写法 --单向数据绑定input typetext v-bind:valuenamebr双向数据绑定input typetext v-model:valuename!-- 简写 --单向数据绑定input typetext :valuenamebr双向数据绑定input typetext v-modelname/divscript typetext/javascript//阻止vue 在启动时生成生产提示Vue.config.productionTipfalse//创建Vue实例new Vue({el:#root,//el用于指定当前vue实例为那个容器服务值通常为css选择器字符串data:{ //data中用来存储数据数据供el所指定的容器去使用值我们暂时先写成一个对象name:vue}})/script
/body5、el与data的两种写法
1.e1有2种写法
(1).new Vue时候配置el属性。 (2).先创建Vue实例随后再通过vm.$mount(‘#root’)指定el的值。
2.data有2种写法
(1).对象式 (2).函数式 如何选择: 目前哪种写法都可以以后学习到组件时data必须使用函数式否则会报错
3.一个重要的原则:
出Vue管理的函数一定不要写箭头函数一旦写了箭头函数this就不再是Vue实例了。
如
bodydiv idrooth1你好:{{name}}/h1/divscript typetext/javascript//阻止vue 在启动时生成生产提示Vue.config.productionTipfalse//el的两种写法const v new Vue({//第一种写法 // el:#root, data:{ //data中用来存储数据数据供el所指定的容器去使用值我们暂时先写成一个对象name:vue}})console.log(v)v.$mount(#root)//第二种写法// data的两种写法new Vue({el:#root,//第一种写法 // data的第一种写法对象式data:{ name:vue}//data的第二种写法函数式data:function(){console.log(this)//此处的this是vue实例对象return{name:Vue}}//函数式可以简写成data(){console.log(this)//此处的this是vue实例对象return{name:Vue}}})/script
/body6、 MVVM 模型
M模型(Model) 对应 data 中的数据V视图(View) 模板VM视图模型(ViewModel) Vue 实例对象 观察发现: 1.data中所有的属性最后都出现在了vm身上。 2.vm身上所有的属性 及 Vue原型上所有属性在Vue模板中都可以直接使用。
7、数据代理
1、 Object.defineProperty方法
Object.defineProperty方法是给一个对象添加(定义)属性用的 语法格式 Object.defineProperty(要添加的对象添加的属性名,{配置项(基本配置项和高级配置项)}) bodyscript typetext/javascriptlet obj{x:100}let obj2{y:200}Object.defineProperty(obj2,x,{//基本配置项value:18,enumerable:true,//控制属性是否可以枚举遍历默认为falsewritable:true,//控制属性是否可以被修改默认值为falseconfigurable:true,//控制属性是否可以被删除默认值是false//高级配置项//当有人读取对象的的x属性是get函数就会被调用且返回值就是x的值get(){return obj.x},//当有人修改对象的的x属性是set函数就会被调用且会收到修改的具体值set(value){obj.xvalue}})/script
/body2、数据代理
1、概念
数据代理通过一个对象代理对另一个对象中属性的操作(读/写)
2、Vue中的数据代理:
通过vm对象来代理data对象中属性的操作(读/写)
3、Vue中数据代理的好处:
更加方便的操作data中的数据
4、基本原理:
通过object.defineProperty()把data对象中所有属性添加到vm上。 为每一个添加到vm上的属性都指定一个getter/setter。 在getter/setter内部去操作 (读/写) data中对应的属性
8、事件处理
1、事件的基本使用:
1.使用v-on:xxx 或 xxx 绑定事件其中xxx是事件名: 2.事件的回调需要配置在methods对象中最终会在vm上; 3.methods中配置的函数不要用箭头函数!否则this就不是vm了是windows: 4.methods中配置的函数都是被Vue所管理的函数this的指向是vm 或 组件实例对象; 5.clickdemo”和 clickdemo($event)” 效果一致但后者可以传参:
!DOCTYPE html
html langenheadmeta charsetUTF-8 /meta http-equivX-UA-Compatible contentIEedge /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleDocument/titlescript typetext/javascript src../js/vue.js/script/headbodydiv idrooth1Hello{{name}}/h1button v-on:clickshowInfo点我提示信息/button!-- 简写 --button clickshowInfo1点我提示信息(不传参数)/buttonbutton clickshowInfo2(66,$event)点我提示信息( 传参数)/button/divscript typetext/javascript//阻止vue 在启动时生成生产提示Vue.config.productionTip false;//创建Vue实例const vm new Vue({el: #root, //el用于指定当前vue实例为那个容器服务值通常为css选择器字符串data: {//data中用来存储数据数据供el所指定的容器去使用值我们暂时先写成一个对象name: vue},methods:{showInfo(event){console.log(event.target.innerText)alert(dddd)},showInfo2(number,event){console.log(event.target.innerText)alert(dddd,number)}}});/script/body
/html
2、事件修饰符
1.prevent: 阻止默认事件 (常用) : 2.stop:阻止事件冒泡 (常用) ; 3.once: 事件只触发一次 (常用) : 4.capture:使用事件的捕获模式; 5.self: 只有event.target是当前操作的元素时才触发事件; 6.passive:事件的默认行为立即执行无需等待事件回调执行完毕: 注意 修饰符可以连续写 如 click.prevent.stop“showInfo”
!DOCTYPE html
html langenheadmeta charsetUTF-8 /meta http-equivX-UA-Compatible contentIEedge /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleDocument/titlescript typetext/javascript src../js/vue.js/scriptstyle* {margin-top: 20px;}.demo1 {height: 50px;background-color: skyblue;}.box1 {padding: 5px;background-color: skyblue;}.box2 {padding: 5px;background-color: antiquewhite;}.list{width: 200px;height: 200px;background-color: bisque;overflow: auto;}li{height: 100px;}/style/headbody!--Vue中的事件修饰符:1.prevent: 阻止默认事件 (常用) :2.stop:阻止事件冒泡 (常用) ;3.once: 事件只触发一次 (常用) :4.capture:使用事件的捕获模式;5.self: 只有event.target是当前操作的元素时才触发事件;6.passive:事件的默认行为立即执行无需等待事件回调执行完毕:--div idrooth1Hello{{name}}/h1!-- 阻止默认事件常用 --a hrefwww.baidu.com click.preventshowInfo点我提示信息/a!-- 阻止事件冒泡常用 --div classdemo1 clickshowInfobutton click.stopshowInfo点我提示信息/button/div!-- once: 事件只触发一次 (常用) --button click.onceshowInfo点我提示信息/button!-- capture:使用事件的捕获模式 --div classbox1 click.captureshowMsg()1div1div classbox2 clickshowMsg(2)div2/div/div!-- elf: 只有event.target是当前操作的元素时才触发事件 --div classdemo1 click.elfshowInfobutton clickshowInfo点我提示信息/button/div!-- passive:事件的默认行为立即执行无需等待事件回调执行完毕 --!-- scroll 滚动条滚动事件wheel鼠标滚轮滚事件--ul classlist scrolldemoli1/lili2/lili3/lili4/li/ul/divscript typetext/javascript//阻止vue 在启动时生成生产提示Vue.config.productionTip false;//创建Vue实例const vm new Vue({el: #root, //el用于指定当前vue实例为那个容器服务值通常为css选择器字符串data: {//data中用来存储数据数据供el所指定的容器去使用值我们暂时先写成一个对象name: vue,},methods: {showInfo(event) {console.log(event.target.innerText);alert(dddd);},showMsg(msg) {alert(msg);},demo(){alert(滚动了)}},});/script/body
/html
3、键盘事件
1.Vue中常用的按键别名: 回车 enter 删除 delete (捕获“删除”和“退格”键) 退出 esc 空格 space 换行 tab特殊必须配合keydown使用 上 up 下 down 左 left 右 right 2.Vue未提供别名的按键可以使用按键原始的key值去绑定但注意要转为kebab-case (短横线命名) 3.系统修饰键(用法特殊) : ctr1、alt、shift、meta (1),配合keyup使用: 按下修饰键的同时再按下其他键随后释放其他键事件才被触发。 (2).配合keydown使用: 正常触发事件。 4.也可以使用keyCode去指定具体的按键(不推荐) keyup.13“showInfo” 5.Vue.config.keyCodes.自定义键名 键码可以去定制按键别名 //自定义别名按键 Vue.config.keyCodes.huiche13 !DOCTYPE html
html langenheadmeta charsetUTF-8 /meta http-equivX-UA-Compatible contentIEedge /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleDocument/titlescript typetext/javascript src../js/vue.js/script/headbodydiv idrooth1Hello{{name}}/h1!-- keyup鼠标按下抬起时触发keydown鼠标按下时触发--input typetext placeholder按下回车提示输入 keyup.entershowInfo//divscript typetext/javascript//阻止vue 在启动时生成生产提示Vue.config.productionTip false;//自定义别名按键Vue.config.keyCodes.huiche13//创建Vue实例const vm new Vue({el: #root, //el用于指定当前vue实例为那个容器服务值通常为css选择器字符串data: {//data中用来存储数据数据供el所指定的容器去使用值我们暂时先写成一个对象name: vue,},methods: {showInfo(e) {// if(e.keyCode!13) returnconsole.log(e.target.value);}},});/script/body
/html
9、计算属性与监视
1、计算属性 computed
1.定义:要用的属性不存在要通过已有属性计算得来。 在 computed 对象中定义计算属性。 在页面中使用{{方法名}}来显示计算的结果。 2.原理: 底层借助了objcet,defineproperty方法提供的getter和setter。 3.get函数什么时候执行? (1).初次读取时会执行一次。 (2).当依赖的数据发生改变时会被再次调用。 4.优势:与methods实现相比内部有缓存机制(复用) 效率更高调试方便。 5.备注: 1.计算属性最终会出现在vm上直接读取使用即可。 2.如果计算属性要被修改那必须写set函数去响应修改且set中要引起计算时依赖的数据发生改变 !DOCTYPE html
html langenheadmeta charsetUTF-8 /meta http-equivX-UA-Compatible contentIEedge /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleDocument/titlescript typetext/javascript src../js/vue.js/script/headbodydiv idroot姓input typetext v-modelfirstName/br名input typetext v-modellastName/br全名span{{fullName}}/span/divscript typetext/javascript//阻止vue 在启动时生成生产提示Vue.config.productionTip false;//自定义别名按键Vue.config.keyCodes.huiche13//创建Vue实例const vm new Vue({el: #root, //el用于指定当前vue实例为那个容器服务值通常为css选择器字符串data: {//data中用来存储数据数据供el所指定的容器去使用值我们暂时先写成一个对象firstName: vue,lastName:三},computed:{// 完整写法fullName:{//get的作用当有人读取fullName时get就会被调用且返回值就作为fullName的值//get什么时候调用1、初次读取fullName时。2、所依赖的数据发生变化时get(){return this.firstName-this.lastName},//set什么时候调用当fullName被修改时set(value){const arr value.split(-)this.firstNamearr[0]this.lastNamearr[1]}}//简写 只考虑读取不考虑修改时才能用fullName(){return this.firstName-this.lastName}}})/script/body
/html
2、监视属性
通过 vm 对象的$watch()或 watch 配置来监视指定的属性当属性变化时, 回调函数自动调用, 在函数内部进行计算
1、监视属性 watch及简写方式:
1.当被监视的属性变化时回调函数自动调用进行相关操作 2.监视的属性必须存在才能进行监视 3.监视的两种写法: (1).new Vue时传入watch配置当创建实例时很明确监视谁时用 (2).通过vm.$watch监视当创建实例时很不明确监视谁时用 !DOCTYPE html
html langenheadmeta charsetUTF-8 /meta http-equivX-UA-Compatible contentIEedge /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleDocument/titlescript typetext/javascript src../js/vue.js/script/headbodydiv idrooth2今天天气很{{info}}/h2!-- 绑定事件的时候 xxxyyy yyy可以写一些简单的语句 --button clickisHot!isHot切换天气1/buttonbutton clickchangWeather切换天气/button/divscript typetext/javascript//阻止vue 在启动时生成生产提示Vue.config.productionTip false;//自定义别名按键Vue.config.keyCodes.huiche13//创建Vue实例const vm new Vue({el: #root, //el用于指定当前vue实例为那个容器服务值通常为css选择器字符串data: {isHot:true},methods: {changWeather(){this.isHot!this.isHot}},computed:{info(){return this.isHot?炎热:凉爽}},//当创建实例时很明确监视谁时用//正常写法isHot:{//immediate:false,//初始化时让handler调用一下//deep:true,//深度监视//handler什么时候调用当isHot发生改变时handler(newValue,oldValue){console.log(isHot被修改了,newValue,oldValue)}, },//简写形式 前提是没有其他配置项只有hander是才能用isHot(newValue,oldValue){console.log(isHot被修改了,newValue,oldValue)},});//正常写法//当创建实例时很不明确监视谁时用vm.$watch(isHot,{immediate:false,//初始化时让handler调用一下//handler什么时候调用当isHot发生改变时handler(newValue,oldValue){console.log(isHot被修改了,newValue,oldValue)}})//简写vm.$watch(isHot,function(newValue,oldValue){console.log(isHot被修改了,newValue,oldValue)})/script/body
/html1、深度监听 deep
(1).Vue中的watch默认不监测对象内部值的改变 (一层) (2).配置deeptrue可以监测对象内部值改变(多层)。 备注: (1).Vue自身可以监测对象内部值的改变但vue提供的watch默认不可以! (2).使用watch时根据数据的具体结构决定是否采用深度监视。
!DOCTYPE html
html langenheadmeta charsetUTF-8 /meta http-equivX-UA-Compatible contentIEedge /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleDocument/titlescript typetext/javascript src../js/vue.js/script/headbodydiv idrooth2今天天气很{{info}}/h2!-- 绑定事件的时候 xxxyyy yyy可以写一些简单的语句 --button clickisHot!isHot切换天气1/buttonbutton clickchangWeather切换天气/buttonhr/h3a的值是{{numbers.a}}/h3button clicknumbers.a点我让a1/buttonhr/h3b的值是{{numbers.b}}/h3button clicknumbers.b点我让b1/button/divscript typetext/javascript//阻止vue 在启动时生成生产提示Vue.config.productionTip false;//自定义别名按键Vue.config.keyCodes.huiche13//创建Vue实例const vm new Vue({el: #root, //el用于指定当前vue实例为那个容器服务值通常为css选择器字符串data: {isHot:true,numbers:{a:1,b:1}},methods: {changWeather(){this.isHot!this.isHot}},computed:{info(){return this.isHot?炎热:凉爽}},//当创建实例时很明确监视谁时用watch:{isHot:{//immediate:false,//初始化时让handler调用一下//handler什么时候调用当isHot发生改变时handler(newValue,oldValue){console.log(isHot被修改了,newValue,oldValue)}, },//监视多级结构中某个属性的变化number.a:{handler(){console.log(a被改变了)}, },//监视多级结构中所有属性的变化numbers:{deep:true,handler(){console.log(a被改变了)},}}});/script/body
/html
3、计算属性computed和监听属性watch的对比
computed利lwatch之间的区别: 1.computed能完成的功能watch都可以完成。 2.watch能完成的功能computed不一定能完成例如: watch可以进行异步操作。 两个重要的小原则: 1.所被Vue管理的函数最好写成普通函数这样this的指向才是vm 或 组件实例对象。 2.所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等)最好写成箭头函数,这样this的指向才是vm 或 组件实例对象。
10、class 与style的绑定
1。class样式 写法:classxxxxx可以是宁符串、对象、数组。 字符串写法适用于:类名不确定要动态获取。 对象写法适用于:要绑定多个样式个数不确定名字也不确定。 数组写法适用于:要绑定多个样式个数确定名宁也确定但不确定用不用, 2。style样式 :style(fontsize: xxx]“其中xxx是动态值。 :style”[a,b]其中a、b是样式对象。 !DOCTYPE html
html langenheadmeta charsetUTF-8 /meta http-equivX-UA-Compatible contentIEedge /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleDocument/titlescript typetext/javascript src../js/vue.js/scriptstyle.basic{}.happy{}.sad{}/style/headbodydiv idroot!-- 绑定class样式--字符串写法适用于:样式的类名不确定需要动态指定 --div classbasic :classmood clickchanageMood{{name}}/div!-- 绑定class样式--数组写法适用于:要绑定的样式个数不确定、名字也不确定 --div classbasic :classclassArr{{name}}/divI!-- 绑定class样式--对象写法适用于:要绑定的样式个数确定、名字也确定但要动态决定用不用 --div classbasic :classcalssObj{{name}}/divI!-- 绑定style样式--对象写法 --div classbasic :stylestyleObj{{name}}/divI/divscript typetext/javascript//阻止vue 在启动时生成生产提示Vue.config.productionTip false;//创建Vue实例const vm new Vue({el: #root, //el用于指定当前vue实例为那个容器服务值通常为css选择器字符串data: {name:Vue,mood:normal,classArr:[style1,style2,style3],classObj:{class1:false,class2:false},styleObj:{fontSize:40px,color:red,backgroundColor:orange}},methods: {chanageMood(){this.mood变换后的class名}},});/script/body
/html
11、条件渲染
1.V-if
写法: (1).v-if“表达式” (2).V-else-if“表达式” (3).v-else“表达式” 适用于:切换频率较低的场景。 特点:不展示的DOM元素直接被移除。 注意:v-if可以和:v-else-if、v-else一起使用但要求结构不能被“打断” 2.V-show 写法:v-show表达式适用于:切换频率较高的场景。 特点:不展示的DOM元素术被移除仅仅是使用样式隐藏掉 3.备注:
使用v-if的时元素可能无法获取到而使用v-show一定可以获取到。
!DOCTYPE html
html langenheadmeta charsetUTF-8 /meta http-equivX-UA-Compatible contentIEedge /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleDocument/titlescript typetext/javascript src../js/vue.js/scriptstyle/style/headbodydiv idroot!-- 使用v-show做条件渲染 --h2 v-showfalse欢迎来到{{name}}/h2!-- 使用v-if做条件渲染 --h2 v-iffalse欢迎来到{{name}}/h2!-- v-else利v-else-if --div v-ifn 1Angular/divdiv/div//等于打断了div v-else-ifn 2React/divdiv v-else-ifn 3Vue/divdiv v-else哈哈/div!-- template模板不影响代码结构 v-if与template的配合使用 --template v-ifn1h2dddd/h2h2dddd/h2h2dddd/h2/template/divscript typetext/javascript//阻止vue 在启动时生成生产提示Vue.config.productionTip false;//创建Vue实例const vm new Vue({el: #root, //el用于指定当前vue实例为那个容器服务值通常为css选择器字符串data: {name:Vue,}});/script/body
/html
12、列表渲染
v-for指令
1.用于展示列表数据 2.语法: v-for(itemindex) in xxx”:key“index” 或 v-foritem in xxx”:key“item.id” 3.可遍历: 数组、对象、字符串(用的很少)、指定次数(用的很少)
!DOCTYPE html
html langenheadmeta charsetUTF-8 /meta http-equivX-UA-Compatible contentIEedge /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleDocument/titlescript typetext/javascript src../js/vue.js/scriptstyle/style/headbodydiv idroot!-- 遍历数组 --h2人员列表遍历数组/h2ul!-- key的写法一li v-forperson in persons :keyperson.id --!-- key的写法二 li v-for(person,index) in persons ::keyindex --li v-for(person,index) in persons :keyindex{{person.name}}-{{person.age}}/li/ul!-- 遍历对象 --h2汽车信息遍历对象/h2ulli v-for(value,k) in car :keyk{{k}}----{{value}}/li/ul!-- 遍历字符串 --h2测试遍历字符串用的少/h2ulli v-for(value,k) in str :keyk{{k}}----{{value}}/li/ul!-- 遍历指定次数 --h2测试遍历指定次数用的少/h2ulli v-for(value,k) in 5 :keyk{{k}}----{{value}}/li/ul/divscript typetext/javascript//阻止vue 在启动时生成生产提示Vue.config.productionTip false;//创建Vue实例const vm new Vue({el: #root, //el用于指定当前vue实例为那个容器服务值通常为css选择器字符串data: {persons:[{id:001,name:张三1,age:18},{id:002,name:张三2,age:188},{id:003,name:张三3,age:198}],car:{name:奥迪A3,price:18万},str:hello world}});/script/body
/html
1、遍历列表时key的作用index作为key 2、遍历列表时key的作用id作为key 3、面试题: react、vue中的key有什么作用? (key的内部原理)
1。虚拟DOM中key的作用: key是虚拟DOM对象的标识当状态中的数据发生变化时Vue会根据[新数据]生成[新的虚拟DOM]随后Vue进行[新虚拟DOM] 与[旧虚拟DOM] 的差异比较比较规则如下: 2.对比规则:
(1).旧虚拟DOM中找到了与新虚拟DOM相同的key: 若虚拟DOM中内容没变直接使用之前的真实DOM! 若虚拟DOM中内容变了则生成新的真实DOM随后替换掉贞面中之前的真实DOM. (2).旧虚拟DOM中未找到与新虚拟DOM相同的key 创建新的真实DOM随后渲染到到页面。
3。用index作为key可能会引发的问题:
1。若对数据进行:逆序添加、逆序删除等破坏顺序操作:会产生没有必要的真实DOM更新 界面效果没问题但效率低。2。如果结构中还包含输入类的DOM:会产生错误DOM更新 界面有问题。
4。开发中如何选择key?:
1.最好使用每条数据的唯一标识作为key比如id、手机号、身份证号、学号等唯一值。2.如果不存在对数据的逆序添加、逆序删除等破坏顺序操作仅用于渲染列表用于展示使用index作为key是没有问题的。
13、列表过滤
!DOCTYPE html
html langenheadmeta charsetUTF-8 /meta http-equivX-UA-Compatible contentIEedge /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleDocument/titlescript typetext/javascript src../js/vue.js/scriptstyle/style/headbodydiv idroot!-- 遍历数组 --h2人员列表遍历数组/h2input typetext placeholder请输入名字 v-modelkeyworkd/ulli v-for(person,index) in filPersons :keyindex{{person.name}}-{{person.age}}/li/ul/divscript typetext/javascript//阻止vue 在启动时生成生产提示Vue.config.productionTip false;//watch实现/* const vm new Vue({el: #root, //el用于指定当前vue实例为那个容器服务值通常为css选择器字符串data: {keyworkd:,filPersons:[],persons:[{id:001,name:张三1,age:18},{id:002,name:张三2,age:188},{id:003,name:张三3,age:198}]},watch:{keyworkd:{immediate:true,handler(val){this.filPersons this.persons.filter((p){return p.name.indexOf(val) ! -1})}}}}); *///用computed实现const vm new Vue({el: #root, //el用于指定当前vue实例为那个容器服务值通常为css选择器字符串data: {keyworkd:,persons:[{id:001,name:张三1,age:18},{id:002,name:张三2,age:188},{id:003,name:张三3,age:198}]},computed:{filPerons(){return this.persons.filter((p){return p.name.indexOf(this.keyworkd) ! -1})}}});/script/body
/html
14、列表排序
!DOCTYPE html
html langenheadmeta charsetUTF-8 /meta http-equivX-UA-Compatible contentIEedge /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleDocument/titlescript typetext/javascript src../js/vue.js/scriptstyle/style/headbodydiv idroot!-- 遍历数组 --h2人员列表遍历数组/h2input typetext placeholder请输入名字 v-modelkeyworkd/button clicksortType2升序/buttonbutton clicksortType1降序序/buttonbutton clicksortType0原序/buttonulli v-for(person,index) in filPersons :keyindex{{person.name}}-{{person.age}}/li/ul/divscript typetext/javascript//阻止vue 在启动时生成生产提示Vue.config.productionTip false;//watch实现/* const vm new Vue({el: #root, //el用于指定当前vue实例为那个容器服务值通常为css选择器字符串data: {keyworkd:,filPersons:[],persons:[{id:001,name:张三1,age:18},{id:002,name:张三2,age:188},{id:003,name:张三3,age:198}]},watch:{keyworkd:{immediate:true,handler(val){this.filPersons this.persons.filter((p){return p.name.indexOf(val) ! -1})}}}}); *///用computed实现const vm new Vue({el: #root, //el用于指定当前vue实例为那个容器服务值通常为css选择器字符串data: {keyworkd:,sortType:0,//0代表原顺序 1 降序 2 升序persons:[{id:001,name:张三1,age:18},{id:002,name:张三2,age:188},{id:003,name:张三3,age:198}]},computed:{filPerons(){const arr this.persons.filter((p){return p.name.indexOf(this.keyworkd) ! -1})if(this.sortType){arr.sort((p1,p2){return this.sortType1?p2.age-p1.age:p1.age-p2.age})}return arr}}});/script/body
/html
15、vue检测数据的原理
1vue会监视data中所有层次数据。 2。如何监测对象中的数据? 通过setter实现监视且要在new Vue时就传入要监测的数据。 (1).对象中后追加的属性Vue默认不做响应式处理 (2).如需给后添加的属性做响应式请使用如下API: Vue.set(targetpropertyName/index value) 或 vm.$set(targetpropertyName/indexvalue) 3如何监测数组中的数据? 通过包裹数组更新元素的方法实现本质就是做了两件事: (1).调用原生对应的方法对数组进行更新。 (2).重新解析模板进而更新页面。 4.在Vue修改数组中的某个元素一定要用如下方法: 1.使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse() 2.Vue.set() 或 vm.$set() 特别注意: Vue.set() 和 vm.$set() 不能给vm 或 vm的根数据对象 添加属性
16、收集表单数据
若:input typetext/则v-model收集的是value值用户输入的就是value值。
若:input typeradio/则v-model收集的是value值且要给标签配置value值
若: input typecheckbox/1.没有配置input的value属性那么收集的就是checked (勾选 or 未勾选是布尔值)2.配置input的value属性:(1)v-model的初始值是非数组那么收集的就是checked(勾选 or 未勾选是布尔值)(2)v-model的初始值是数组那么收集的的就是value组成的数组
备注:v-model的三个修饰符:lazy:失去焦点再收集数据number:输入字符串转为有效的数字trim:输入首尾空格过滤!DOCTYPE html
html langenheadmeta charsetUTF-8 /meta http-equivX-UA-Compatible contentIEedge /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleDocument/titlescript typetext/javascript src../js/vue.js/scriptstyle/style/headbodydiv idrootform submitdemo //绑定提交事件账号 input typetext v-model.trimaccount/br密码input typepassword v-modelpassword/br年龄:input typenumber v-model.numberage/br性别男input typeradio namesex value男 checked v-modelsex/女input typeradio namesex value女 v-modelsex/br爱好学习input typecheckbox value学习 v-modelhobby学习1input typecheckbox value学习1 v-modelhobby学习2input typecheckbox value学习2 v-modelhobbybr所属校区:select v-modelcityoption value请选择校区/optionoption value11/optionoption value22/optionoption value33/option/selectbr其他textarea v-model.lazyother/textareabrinput typecheckbox v-modelagree 阅读并接受a hrefwww.baidu.com用户协议/abrbutton提交/button/form/divscript typetext/javascript//阻止vue 在启动时生成生产提示Vue.config.productionTip false;const vm new Vue({el: #root, //el用于指定当前vue实例为那个容器服务值通常为css选择器字符串data: {account:,password:,sex:,age:,hobby:[],city:,other:,agree:},methods: {demo(){console.log(JSON.stringify(this._data))}},});/script/body
/html
17、过滤器
定义:对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理)
语法:1.注册过滤器:Vue.filter(name,callback) 或 new Vue{filters:{}}2.使用过滤器:{{ xxx | 过滤器名}} 或 v-bind:属性 “xxx | 过滤器名
备注:1.过滤器也可以接收额外参数、多个过滤器也可以串联2.并没有改变原本的数据是产生新的对应的数据!DOCTYPE html
html langenheadmeta charsetUTF-8 /meta http-equivX-UA-Compatible contentIEedge /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleDocument/titlescript typetext/javascript src../js/vue.js/scriptscript typetext/javascript src../js/dayjs.min.js/scriptstyle/style/headbodydiv idrooth1显示格式化后的时间/h1!-- 计算属性实现 --现在是:h2{{time}}/h2!-- methods实现 --现在是:h2{{getFmtTime()}}/h2!-- 过滤器实现 (不传参数)--现在是:h2{{time | timeFormater}}/h2!-- 过滤器实现 (传参数)--现在是:h2{{time | timeFormater(yyyy_MM_DD) |mySlice }}/h2/divscript typetext/javascript//阻止vue 在启动时生成生产提示Vue.config.productionTip false;//全局过滤器Vue.filter(mySlice,function(value){return value.slice(0,4)})const vm new Vue({el: #root, //el用于指定当前vue实例为那个容器服务值通常为css选择器字符串data: {time:1621561377603},//计算属性实现computed:{fmtTime(){return dayjs(this.time).format(yyyy-MM-DD HH:mm:ss)}},//methods实现 methods: {getFmtTime(){return dayjs(this.time).format(yyyy-MM-DD HH:mm:ss) }},//过滤器实现,(局部过滤器)filters:{ //过滤器配置项timeFormater(value,stryyyy-MM-DD HH:mm:ss){return dayjs(value).format(str) },mySlice(value){return value.slice(0,4)}}});/script/body
/html
18、内置指令与自定义指令
1、常用内置指令
v-text指令: 1.作用:向其所在的节点中渲染文本内容。会替换内容可以解析html标签 2.与插值语法的区别: v-text会替换掉节点中的内容{[xx}}则不会 v-html 和v-text一样 v-html: 和v-text一样但能解析html标签 1.作用:向指定节点中渲染包含htm1结构的内容。 2.与插值语法的区别: (1).v-htm1会替换掉节点中所有的内容{{xx}}则不会 (2).v-htm1可以识别htm1结构。 3.严重注意: v-html有安全性问题!!! ! (1).在网站上动态渲染任意HTML是非常危险的容易导致XSS攻击。 (2).一定要在可信的内容上使用v-htm1永不要用在用户提交的内容上! v-cloak (没有值) : 1.本质是一个特殊属性Vue实例创建完毕并接管容器后会厕掉v-cloak属性。 2.使用css配合v-cloak可以解决网速慢时页面展示出{[xxx}}的问题。 v-once指令: 1.v-once所在节点在初次动态渲染后就视为静态内容了。 2.以后数据的改变不会引起v-once所在结构的更新可以用于优化性能。 V-pre(没有值) 1.跳过其所在节点的编译过程。 2.可利用它跳过:没有使用指令语法、没有使用插值语法的节点会加快编译 !DOCTYPE html
html langenheadmeta charsetUTF-8 /meta http-equivX-UA-Compatible contentIEedge /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleDocument/titlescript typetext/javascript src../js/vue.js/scriptscript typetext/javascript src../js/dayjs.min.js/scriptstyle/* v-cloak用 */[v-cloak]{display: none;}/style/headbodydiv idrootdiv v-textname/divdiv v-htmlstr/divh1 v-cloak{{name1}}/h1h2 v-once初始的n值是{{n}}/h2h2当前的n值是{{n}}/h2button clickn点我n1/buttonh1 v-preVue不简单/h1/divscript typetext/javascript//阻止vue 在启动时生成生产提示Vue.config.productionTip false;const vm new Vue({el: #root, //el用于指定当前vue实例为那个容器服务值通常为css选择器字符串data: {name:vue,str:h1xxxxx/h1,name1:pppp,n:1},});/script/body
/html
19、自定义指令
1、自定义指令总结: 2、自定义指令案例函数式及对象式
需求1:定义个v-big指令莉v-text功能类似但会把绑定的数值放大10倍。 需求2: 定义一个v-fbind指令和v-bind功能类似但可以让其所绑定的input元素默认获取焦点。
!DOCTYPE html
html langenheadmeta charsetUTF-8 /meta http-equivX-UA-Compatible contentIEedge /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleDocument/titlescript typetext/javascript src../js/vue.js/scriptscript typetext/javascript src../js/dayjs.min.js/scriptstyle/style/headbodydiv idrooth1当前的n值是span v-textn/span/h1h1放大10倍后的值span v-bign/span/h1button clickn点我n1/button/divscript typetext/javascript//阻止vue 在启动时生成生产提示Vue.config.productionTip false;//自定义全局指令Vue.directives(fbind,{//指令与元素成功绑定时bind(element,binding){element.valuebinding.value},//指令所在元素被插入页面时inserted(element,binding){element.focus()},//指令所在的模板被重新解析时update(element,binding){element.valuebinding.value}})const vm new Vue({el: #root, //el用于指定当前vue实例为那个容器服务值通常为css选择器字符串data: {n:1},//自定义big指令 局部指令directives:{//big何时调用1、指令与元素成功绑定时 2、指令所在的模板被重新解析时数据发生改变时//函数式big(element,binding){element.innerTextbinding.value*10 },//对象式fbind:{//指令与元素成功绑定时bind(element,binding){element.valuebinding.value},//指令所在元素被插入页面时inserted(element,binding){element.focus()},//指令所在的模板被重新解析时update(element,binding){element.valuebinding.value}}}});/script/body
/html20、生命周期
1.又名:生命周期回调函数、生命周期函数、生命周期钩子。 2.是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数。 3.生命周期函数的名字不可更改但函数的具体内容是程序员根据需求编写的。 4.生命周期函数中的this指向是vm 或 组件实例对象。
1、vm的生命周期
将要创建调用beforeCreate函数 创建完毕调用created函数。 将要挂载调用beforeMount函数。 挂载完毕调用mounted函数。 将要更新调用beforeUpdate函数 更新完毕调用updated函数。 将要销毁调用beforeDestroy函数 销毁完毕调用destroyed函数。
2、常用的生命周期钩子:
1.mounted: 发送ajax请求、启动定时器、绑定自定义事件、订阅消息等[初始化操作] 2.beforeDestroy: 清除定时器、解绑自定义事件、取消订阅消息等[收尾工作]。
3、关于销毁Vue实例
1.销毁后借助Vue开发者工具看不到任何信息。 2.销毁后自定义事件会失效但原生DOM事件依然有效。 3.一般不会beforeDestroy操作数据因为即便操作数据也不会再触发更新流程了。
常用指令总结 v-bind单向绑定解析表达式可简写为 :xxxv-model双向数据绑定v-for遍历数组/对象/字符串v-on绑定事件监听可简写为v-if条件渲染(动态控制节点是否存存在)V-else条件渲染(动态控制节点是否存存在)V-show条件渲染 (动态控制节点是否展示)v-text:向其所在的标签插入文本v-text1.作用:向其所在的节点中渲染文本内容。会替换内容2.与插值语法的区别: v-text会替换掉节点中的内容{[xx}}则不会v-html: 和v-text一样但能解析html标签1.作用:向指定节点中渲染包含htm1结构的内容。2.与插值语法的区别:(1).v-htm1会替换掉节点中所有的内容{{xx}}则不会(2).v-htm1可以识别htm1结构。3.严重注意: v-html有安全性问题!!! !(1).在网站上动态渲染任意HTML是非常危险的容易导致XSS攻击。(2).一定要在可信的内容上使用v-htm1永不要用在用户提交的内容上!v-cloak (没有值) :1.本质是一个特殊属性Vue实例创建完毕并接管容器后会厕掉v-cloak属性。2.使用css配合v-cloak可以解决网速慢时页面展示出{[xxx}}的问题。v-once(没有值)1.v-once所在节点在初次动态渲染后就视为静态内容了。2.以后数据的改变不会引起v-once所在结构的更新可以用于优化性能。V-pre(没有值)1.跳过其所在节点的编译过程。2.可利用它跳过:没有使用指令语法、没有使用插值语法的节点会加快编译
第 2 章Vue 组件化编程
1、 模块与组件、模块化与组件化
1. 模块
1.理解: 向外提供特定功能的 js 程序, 一般就是一个 js 文件 2. 为什么: js 文件很多很复杂 3. 作用: 复用 js, 简化 js 的编写, 提高 js 运行效率
2. 组件
1.理解: 用来实现局部(特定)功能效果代码和资源的集合(html/css/js/image……) 2. 为什么: 一个界面的功能很复杂 3. 作用: 复用编码, 简化项目编码, 提高运行效率
3. 模块化
当应用中的 js 都以模块来编写的, 那这个应用就是一个模块化的应用。
4. 组件化
当应用中的功能都是多组件的方式来编写的, 那这个应用就是一个组件化的应用,。
2、非单文件组件
1、概念
非单文件组件一个文件中包含有n个组件 单文件组件一个文件中只包含有1一个组件
3、Vue中使用组件的三大步骤:
一、定义组件(创建组件) 二、注册组件 三、使用组体(写组件标签)
一、 如何定义一个组件
使用Vue.extend(options)创建其中options和new Vue(options)时传入的那个options几乎一样但也有点区别:区别如下: 1、el不要写为什么? 最终所有的组件都要经过一个vm的管理由vm中的el决定服务哪个容器。 2、data必须写成函数为什么? 避免组件被复用时数据存在引用关系。 备注:使用template可以配置组件结构。
二、如何注册组件?
1.局部注册: 靠new Vue的时候传入components选项 2.全局注册:靠Vue.component(组件名,组件)
三、编写组件标签:
school/schoo1例如
!DOCTYPE html
html langenheadmeta charsetUTF-8 /meta http-equivX-UA-Compatible contentIEedge /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleDocument/titlescript typetext/javascript src../js/vue.js/scriptscript typetext/javascript src../js/dayjs.min.js/scriptstyle/style/headbodydiv idroot!-- 第三步编写组件标签 --school/school/divscript typetext/javascript//阻止vue 在启动时生成生产提示Vue.config.productionTip false;//第一步创建school组件const school Vue.extend({// el: #root,//组件定义时一定不要写el配置项因为最终所有的组件都要被一个vm管理由vm决定服务于哪个容器data() {return {schoolName: 学校,address: xxxx,};},template:divh2学习名称{{schoolName}}/h2h2学习地址{{address}}/h2button clickshowName点我提示学校名/button/div,methods: {showName(){alert(this.schoolName)}},});//第一步创建hello组件const he VUe.extend({name:cy,//可以使用name配置项指定组件在开发者工具中呈现的名字。template:divh2你好呀{{name}}/h2 /div,data(){return {name:TOM}}})//第二步注册组件全局注册Vue.component(hello,he)new Vue({el: #root, //el用于指定当前vue实例为那个容器服务值通常为css选择器字符串//第二步注册组件局部注册components:{school:school//可以简写// school}})/script/body
/html
4、组件的几个注意事项
1.关于组件名:
一个单词组成: 第一种写法(首字母小写)school 第二种写法(首字母大写) school 多个单词组成: 第一种写法(kebab-case命名): my-school 第二种写法(CamelCase命名): MySchool (需要Vue脚手架支持) 备注: (1).组件名尽可能回避HTML中己有的元素名称例如: h2、H2都不行。 (2).可以使用name配置项指定组件在开发者工具中呈现的名字。 2.关于组件标签: 第一种写法: 第二种写法: 备注:不用使用脚手架时会导致后续组件不能渲染 3.一个简写方式:
options表示配置项 { } const school Vue,extend(options) 可简写: const school options 如
//第一步创建hello组件const he {name:cy,//可以使用name配置项指定组件在开发者工具中呈现的名字。template:divh2你好呀{{name}}/h2 /div,data(){return {name:TOM}}}5、组件的嵌套
!DOCTYPE html
html langenheadmeta charsetUTF-8 /meta http-equivX-UA-Compatible contentIEedge /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleDocument/titlescript typetext/javascript src../js/vue.js/scriptscript typetext/javascript src../js/dayjs.min.js/scriptstyle/style/headbodydiv idroot!-- 第三步编写组件标签 --school/schoolhr //divscript typetext/javascript//阻止vue 在启动时生成生产提示Vue.config.productionTip false;//第一步创建student组件const student Vue.extend({data() {return {studentname: 名字,age: 18,};},template:divh2学生名称{{studentname}}/h2h2学习年龄{{age}}/h2/div,});//第一步创建school组件const school Vue.extend({// el: #root,//组件定义时一定不要写el配置项因为最终所有的组件都要被一个vm管理由vm决定服务于哪个容器data() {return {schoolName: 学校,address: xxxx,};},template:divh2学习名称{{schoolName}}/h2h2学习地址{{address}}/h2student/student //引入student组件button clickshowName点我提示学校名/button/div,methods: {showName(){alert(this.schoolName)}},//注册组件局部注册嵌套组件components:{student}});new Vue({el: #root, //el用于指定当前vue实例为那个容器服务值通常为css选择器字符串//第二步注册组件局部注册components:{school:school,//可以简写// school,}})/script/body
/html
6、关丁VueComponent:
1.school组件本质是一个名为VueComponent的构造函数且不是程序员定义的是Vue,extend生成的。
2.我们只需要写school/或schoolx/schoolVue解析时会帮我们创建school组件的实例对象即Vue帮我们执行的: new VueComponent(options)。
3.特别注意: 每次调用Vue.extend返回的都是一个全新的VueComponent!!!!
4.关于this指向:(1).组件配置中:data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是[VueComponent实例对象](2).new Vue()配置中:data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是[Vue实例对象]
5.VueComponent的实例对象以后简称vc (也可称之为: 组件实例对象)。Vue的实例对象以后简称vm。7、一个重要的内置关系:
1.一个重要的内置关系:
VueComponent.prototype._proto_ Vue.prototype2.为什么要有这个关系:
让组件实例对象 (vc) 可以访问到 Vue原型上的属性、方法。
8、单文件组件
1. 一个.vue 文件的组成(3 个部分) // 1、模板页面template!-- 组件的结构 --div/div/template// 2、JS模板对象script//组件交互相关的代码数据、方法/script// 3、样式style /* //组件的样式 *//style如School.vue
// 1、模板页面
template!-- 组件的结构 --div classdemoh2学习名称{{schoolName}}/h2h2学习地址{{address}}/h2button clickshowName点我提示学校名/button/div
/template
// 2、JS模板对象
script//组件交互相关的代码数据、方法export default {name:School,data() {return {schoolName: 学校,address: xxxx,};},methods: {showName(){alert(this.schoolName)}},}
/script// 3、样式
style /* //组件的样式 */.demo{background-color: aliceblue;}
/styleStudent.vue
// 1、模板页面
template!-- 组件的结构 --div classdemoh2学生姓名{{name}}/h2h2学生年龄{{age}}/h2button clickshowName点我提示学名字/button/div
/template
// 2、JS模板对象
script//组件交互相关的代码数据、方法export default {name:School,data() {return {name: 谢谢谢,age: 19,};},methods: {showName(){alert(this.schoolName)}},}
/script// 3、样式
style /* //组件的样式 */.demo{background-color: aliceblue;}
/styleApp.vue
templatedivSchool/SchoolStudent/Student/div
/templatescript//引入组件import School from 01初始vue/单文件组件/Schoolimport Student from 01初始vue/单文件组件/Studentexport default {name:App,//注册组件components:{School,Student}}
/scriptstyle/stylemain.js
import App from 01初始vue/单文件组件/Appnew Vue({el:#root,template:App/App,components:{App}
})index.html
!DOCTYPE html
html langen
headmeta charsetUTF-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0titleDocument/title
/head
body!-- 准备一个容器 --div idroot/div!-- script typetext/javaScript src../../js/vue.js/scriptscript typetext/javaScript src./main.js/script --
/body
/html第 3 章使用 Vue 脚手架
1 初始化脚手架
1、说明
1.Vue 脚手架是 Vue 官方提供的标准化开发工具开发平台。 2. 最新的版本是 4.x。 3. 文档: https://cli.vuejs.org/zh/。
2 、具体步骤
第一步仅第一次执行全局安装vue/cli。
npm install -g vue/cli第二步切换到你要创建项目的目录然后使用命令创建项目
vue create xxxx第三步启动项目
npm run serve备注
1.如出现下载缓慢请配置 npm 淘宝镜像
npm config set registry https://registry.npm.taobao.org2.Vue 脚手架隐藏了所有 webpack 相关的配置若想查看具体的webpakc 配置请执行
vue inspect output.js3 模板项目的结构 4、关于不同版本的Vue:
1.vue.js与vue.runtime.xxx.js的区别: (1).vue.js是完整版的Vue包含: 楼心功能模板解析器。 (2).vue.runtime.xxx.js是运行版的Vue只包含: 核心功能;没有模板解析器. 2.因为vue.runtime.xxx.js没有模板解析器所以不能使用template配置项需要使用render函数接收到的createElement函数去指定具体内容。
2 ref 与 props
1、ref
1.被用来给元素或子组件注册引用信息I(id的替代者) 2.应用在htm1标签上获取的是真实DOM元素应用在组件标签上是组件实例对象 (vc) 3.使用方式:
打标识: h1 refxxx...../h1 或School refxxx/Schoo1
获取: this.$refs.xxx如
templatedivSchool/SchoolStudent refstud/Studenth1 v-textmsg reftitle/h1button clickshowDOM点我输入h2的DOM元素/button/div
/templatescript//引入组件import School from /components/Schoolimport Student from /components/Studentexport default {name:App,//注册组件components:{School,Student},data(){return{msg:欢迎回来}},methods:{showDOM(){console.log(this.$refs.title) //真实的DOM元素h1欢迎回来/h1console.log(this.$refs.stud) //VC的组件实例对象}}}
/scriptstyle/style2、props
1.作用用于父组件给子组件传递数据 2. 读取方式一: 只指定名称
props: [name, age, setName]3.读取方式二: 指定名称和类型
props: {name: String,age: Number, setNmae: Function
}4.读取方式三: 指定名称/类型/必要性/默认值
props: {name: {type: String, required: true, default:xxx},
}5.传递数据:
Student namexxx age18/备注: props是只读的Vue底层会监测你对props的修改如果进行了修改就会发出警告若业务需求确实需要修改那么请复制props的内容到data中一份然后去修改data中的数据。
如 传值
templatedivStudent name学生1 age19/ //传值/div
/templatescript//引入组件import Student from /components/Studentexport default {name:App,//注册组件components:{Student}}
/scriptstyle/style接收值
// 1、模板页面
template!-- 组件的结构 --div classdemo h2 v-textmsg/h2h2学生姓名{{name}}/h2h2学生年龄{{myAge}}/h2button clickupdateage点我修改年龄/button /div
/template
// 2、JS模板对象
script//组件交互相关的代码数据、方法export default {name:Student,data() {return {msg:我是学生,myAge:this.age};},methods:{updateage(){this.myAge}},//方式一简单接受// props:[name,age] //方式二接收的同时对数据进行类型限制/* props:{name:String,age:Number} *///方式三接收的同时指定名称/类型/必要性/默认值props:{name:{type:Stirng,//name的类型是字符串required:true //name是必要的},age:{type:Number,default:99//默认值}}}
/script// 3、样式
style /* //组件的样式 */.demo{background-color: aliceblue;}
/style3 混入minxin
功能可以把多个组件共用的配置提取成一个混入对象 使用方式: 第一步自定义混合例如:
{data()(....},methods:{....]
}
第二步使用混入例如: (1).全局混入: Vue.mixin(xxx) (2).局部混入: mixins:[‘xxx’]
如 第一步自定义混合mixin.js文件
export const hunhe{methods: {showName(){alert(this.schoolName)}}
}第二步使用混入
script// 局部引用import {hunhe} from ../minxin//组件交互相关的代码数据、方法export default {name:School,data() {return {schoolName: 学校,address: xxxx,};},mixins:[hunhe]}
/script再main.js中全局引入
//引入Vue
import Vue from vue
//引入App
import App from ./App.vue
import { hunhe } from ./minxin
//关闭Vue的生产提示
Vue.config.productionTip false//全局引入
Vue.mixin(hunhe)//创建VM
new Vue({render: h h(App),
}).$mount(#app)
4 插件
1、功能:
用于增强Vue
2、本质:
包含install方法的一个对象install的第一个参数是Vue第二个以后的参数是插件使用者传递的数据。
3、定义插件:
对象.install function (Vue, options) {// 1。添加全局过滤器Vue.filter(....)// 2.添加全局指令Vue.directive(....)// 3。配置全局混入(合)Vue.mixin(....)// 4。添加实例方法Vue.prototype.$myMethod function () [...}Vue.prototype.$myProperty xxxx
}如
export default {install(Vue,x,y,z){console.log(x,y,z)//全局过滤器Vue.filter(mySlice,function(value){return value.slice(0,4)})//定义全局指令Vue.directive(fbind,{//指令与元素成功绑定时一上来bind(element,binding){element.value binding.value},//指令所在元素被插入页面时inserted(element,binding){element.focus()},//指令所在的模板被重新解析时update(element,binding){element.value binding.value}})//定义混入Vue.mixin({data() {return {x:100,y:200}},})//给Vue原型上添加一个方法vm和vc就都能用了Vue.prototype.hello (){alert(你好啊)}}
}4、再main.js中使用插件:
Vue.use(插件名)如
//引入Vue
import Vue from vue
//引入App
import App from ./App.vue
//关闭Vue的生产提示
Vue.config.productionTip false//引入插件
import plugins from ./plugins
//使用插件
Vue.use(plugins)//创建VM
new Vue({render: h h(App),
}).$mount(#app)
5、scoped样式
作用:让样式在局部生效防止冲突。 写法:
style scoped//样式
/style6、组件的自定义事件
App.vue
templatediv!-- 通过父组件给子组件传递函数类型的props实现子给父传递数据 --School :getSchoolNamegetSchoolName/!-- 写法一使用或v-on通过父组件给子组件绑定一个自定义事件实现子给父传递数据 --Student v-on:cygetStudentName/!-- 只在第一次起作用 --Student v-on:cy.oncegetStudentName/!-- 写法二使用ref通过父组件给子组件绑定一个自定义事件实现子给父传递数据 --Student refstudent//div
/templatescript//引入组件import Student from /components/Studentimport School from ./components/School.vueexport default {name:App,//注册组件components:{Student,School,},methods:{getSchoolName(name){return this.name},getStudentName(name){console.log(cy事件被触发了)return this.name}},mounted(){// 绑定自定义事件this.$refs.Student.$on(cy,this.getStudentName)// 只在第一次起作用this.$refs.Student.$once(cy,this.getStudentName)}}
/scriptstyle/styleStudent.vue
templatediv classtesth2学生姓名{{name}}/h2h2学生性别{{sex}}/h2button clicksendStudentName把学生名给App/buttonbutton clickunbind解绑cy事件/buttonbutton clickdeath销毁了当前组件就的实例/button/div
/templatescriptexport default {name:Student,data() {return {name:张三,sex:男}},methods:{sendStudentName(){//触发Student组件实例身上的cy事件this.$emit(cy,this.name)},unbind(){//解绑自定义事件只使用与一个自定义事件this.$off(cy)//解绑多个自定义事件this.$off([cy,自定义事件2,xxx])this.$off()//所有的自定义事件全部解绑},death(){this.$destroy()//销毁了当前组件就的实例销毁后该组件实例的自定义事件全部不奏效}}}
/scriptstyle scoped.test{background-color: bisque;}
/style7、全局事件总线 (GlobalEventBus)任意组件间通信
1.一种组件间通信的方式适用于任意组件间通信。 2.安装全局事件总线:
new Vue({。。。。。。。beforeCreate(){Vue.prototype.$bus this //安装全局事件总线$bus就是当前应用的vm},......
})3.使用事件总线: 接收数据:A组件想接收数据则在A组件中给Sbus绑定自定义事件事件的回调留在A组件自身. methods(){demo(data){......}
}
....
mounted() {this.$bus.$on(xxxx,this .demo)
}提供数据: this.$bus.$emit(xxxx’,数据)4.最好在beforeDestroy钩子中用$off去解绑当前组件所用到的事件。
如: 在main.js中 安装全局事件总线
//引入Vue
import Vue from vue
//引入App
import App from ./App.vue
//关闭Vue的生产提示
Vue.config.productionTip false//创建VM
new Vue({render: h h(App),beforeCreate(){Vue.prototype.$busthis //安装全局事件总线}
}).$mount(#app)
将学生名传递给学校组件 Student.vue
templatediv classtesth2学生姓名{{name}}/h2h2学生性别{{sex}}/h2button clicksendStudentName把学生名给School组件/button/div
/templatescriptexport default {name:Student,data() {return {name:张三,sex:男}},methods:{sendStudentName(){//触发Student组件实例身上的cy事件this.$bus.$emit(hello,this.name)}}}
/scriptstyle scoped.test{background-color: bisque;}
/styleSchool.vue组件
templatediv classdemoh2学校名称{{name | mySlice}}/h2h2学校地址{{address}}/h2/div
/templatescriptexport default {name:School,data() {return {name:尚硅谷atguigu,address:北京,}},mounted(){this.$bus.$on(hell,(data){console.log(我是School组件收到了数据,data)})},//beforeDestroy钩子中用$off去解绑当前组件所用到的事件。beforeDestroy(){this.$bus.$off(hello)}}
/script
style .demo{background-color: aqua;}
/style8、消息订阅与发布
1 理解
这种方式的思想与全局事件总线很相似它包含以下操作: (1) 订阅消息 --对应绑定事件监听 (2) 发布消息 --分发事件 (3) 取消消息订阅 --解绑事件监听需要引入一个消息订阅与发布的第三方实现库: PubSubJS
2 使用 PubSubJS
在线文档: https://github.com/mroderick/PubSubJS下载: npm install -S pubsub-js相关语法
(1) import PubSub from pubsub-js // 引入
(2) PubSub.subscribe(‘msgName’, functon(msgName, data){ })
(3) PubSub.publish(‘msgName’, data): 发布消息, 触发订阅的回调函数调用
(4) PubSub.unsubscribe(token): 取消消息的订阅3、总结 如 Student.vue
templatediv classtesth2学生姓名{{name}}/h2h2学生性别{{sex}}/h2button clicksendStudentName把学生名给School组件/button/div
/templatescriptimport pubsub from pubsub-jsexport default {name:Student,data() {return {name:张三,sex:男}},methods:{sendStudentName(){// //触发Student组件实例身上的cy事件// this.$bus.$emit(hello,this.name)pubsub.publish(hello,666)}}}
/scriptstyle scoped.test{background-color: bisque;}
/styleSchool.vue
templatediv classdemoh2学校名称{{name | mySlice}}/h2h2学校地址{{address}}/h2/div
/templatescript// 引入import pubsub from pubsub-jsexport default {name:School,data() {return {name:尚硅谷atguigu,address:北京,}},mounted(){// this.$bus.$on(hell,(data){// console.log(我是School组件收到了数据,data)// })this.pubId pubsub.subscribe(hello,(msgName,data){console.log(有人发布了hello消息hello消息的回调执行了,msgName,data)})},beforeDestroy(){// this.$bus.$off(hello)pubsub.unsubscribe(this.pubId)}}
/script
style .demo{background-color: aqua;}
/stylenextTick
1.语法: this.$nextTick(回调函数) 2.作用: 在下一次 DOM 更新结束后执行其指定的回调 3.什么时候用: 当改变数据后要基于更新后的新DOM进行某些操作时要在nextTick所指定的回调函数中执行.
9 、Vue封装的过度与动画
1、作用在插入、跟新或移除DOM元素时在合适的时候给元素添加样式类名 2、图示 3、写法
准备好样式
元素进入的样式1、v-enter:进入的起点2、v-enter-axtive:进入过程中3、v-enter-to:进入的终点
元素离开的样式1、v-leave:离开的起点2、v-leave-active:离开过程中3、v-leave-to:离开的终点
使用包裹要过渡的元素并配置name属性 transition appear namehelloh1 v-showisShow你好呀/h1/transition备注若有多个元素需要过度则需要使用 transition-group且每个元素都要指定key值 如
templatedivbutton clickisShow !isShow显示/隐藏/button!-- h1 v-showisShow classcome你好呀/h1 --transition appear namehelloh1 v-showisShow你好呀/h1/transition!-- transition-group 可以实现多个元素过度 --transition-group appear namehello h1 v-showisShow key1你好呀/h1h1 v-showisShow key2辰逸/h1/transition-group/div
/template
scriptexport default ({name:Test2,data(){return{isShow:true}}
})
/scriptstyle scopedh1{background-color: orange;/* transition: 05s linear; */}//封装的过度/* 进入的起点、离开的终点*/.hello-enter,.hello-leave-to{transform: translateX(-100%);}/* 进入的终点 、离开的起点*/.hello-enter-to,.hello-leave{transform: translateX(0);}.hello-enter-active,.hello-leave-active{transition: 05s linear;}//封装的动画过度和动画使用一个就可以.v-enter-active{animation:cy 1s}.v-leave-active{animation: cy 1s reverse; }keyframes cy{from{transform: translateX(-100px);}to{transform: translateX(-0px);}}/style第三方动画库 https://www.npmjs.com/网站上搜索animate.css
templatedivbutton clickisShow !isShow显示/隐藏/button!-- h1 v-showisShow classcome你好呀/h1 --transition appear namehelloh1 v-showisShow你好呀/h1/transition!-- transition-group 可以实现多个元素过度 --transition-group appear nameanimate_animated animate_bounceenter-active-classanimate_swingleave-active-classanimate_backOutUph1 v-showisShow key1你好呀/h1h1 v-showisShow key2辰逸/h1/transition-group/div
/template
script
//引入animate
import animate.css
export default ({name:Test2,data(){return{isShow:true}}
})
/scriptstyle scopedh1{background-color: orange;/* transition: 05s linear; */}/style第 4 章Vue 中的 ajax
1 解决开发环境 Ajax 跨域问题代理服务器 2、vue脚手架配置代理
方法一 在vue.config.s中添加如下配置: devServer:{proxy:http://localhost:5000}说明:
优点:配置简单请求资源时直接发给前端 (8080) 即可。缺点:不能配置多个代理不能灵活的控制请求是否走代理工作方式:若按照上述配置代理当请求了前端不存在的资源时那么该请求会转发给服务器(优先匹配前端资源)
方法二 编写vue.config.js配置具体代理规则 devServer: {proxy: {/cy: { //匹配所有以/cy开头的请求路径target: http://localhost:5000,//代理目标的基础路径pathRewrite:{^/cy:}, //去掉请求地址中的/cyws: true, //用于支持websocketchangeOrigin: true //用于控制请求头中的host值},/demo: {//匹配所有以/demo开头的请求路径target: http://localhost:5001,//代理目标的基础路径pathRewrite:{^/demo:},//去掉请求地址中的/demows: true, //用于支持websocketchangeOrigin: true //用于控制请求头中的host值 为true时请求头的host为localhost:5000,为false时localhost:8080 默认为true},}}如 vue.config.js
const { defineConfig } require(vue/cli-service)
module.exports defineConfig({transpileDependencies: true,lintOnSave:false , //关闭语法检查//开启代理服务器方式一/* devServer:{proxy:http://localhost:5000}, *///开启代理服务器方式二devServer: {proxy: {/cy: {target: http://localhost:5000,pathRewrite:{^/cy:}, //去掉请求地址中的/cyws: true, //用于支持websocketchangeOrigin: true //用于控制请求头中的host值},/demo: {target: http://localhost:5001,pathRewrite:{^/demo:},//去掉请求地址中的/demows: true, //用于支持websocketchangeOrigin: true //用于控制请求头中的host值},}}
})
App.vue
templatedivbutton clickgetSutdents获取学生信息/buttonbutton clickgetCars获取汽车信息/button/div!-- http://localhost:5000/studentshttp://localhost:5001/cars--
/templatescriptimport axios from axiosexport default {name:App,methods:{getSutdents(){axios.get(http://localhost:8080/cy/students).then(response{console.log(请求成功了,response.data)},error{console.log(请求失败了,error.message)})},getCars(){axios.get(http://localhost:8080/demo/cars).then(response{console.log(请求成功了,response.data)},error{console.log(请求失败了,error.message)})}}}
/script
3、插槽
1.作用:
让父组件可以向子组件指定位置插入html结构也是一种组件间通信的方式 适用于 父组件 子组件
2.分类:
默认插槽、具名插槽、作用域插槽
3.使用方式
1、默认插槽
父组件中:Categorydivhtml结构1/div/Category
子组件中templatediv!-- 定义插槽 --slot插槽默认内容.../slot/div/template2、具名插槽
父组件中Categorytemplate slotcenter》divhtm1结构1/div/templatetemplate v-slot:footerdivhtml结构2/div/template/Category
子组件中:templatediv!--定义插槽 --slot namecenter插槽默认内容.../slotslot namefooter插槽默认内容.../slot/div/template3.作用域插槽:
1.理解:
数据在组件的自身但根据数据生成的结构需要组件的使用者来决定。 (games数据在Category组件中但使用数据所遍历出来的结构由App组件决定)
2.具体编码
父组件中:Categorytemplate scopescopeData!-- 生成的是u1列表 --ulli v-forg in scopeData.games” :keyg((g)}/1i/u1/template/CategoryCategorytemplate slot-scopescopeData!-- 生成的是h4标题 --h4 v-forg in scopeData.games” :keyg(g]]/h4/template/Category
子组件中templatedivslot :gamesgames/slot/div/templatescriptexport default {name:Category,props:[title],//数据在子组件自身data(){return {games:[红色警戒”穿越火线劲舞团超级玛丽]},/script第 5 章vuex
1、理解 vuex
1 vuex 是什么
概念专门在 Vue 中实现集中式状态数据管理的一个Vue 插件对vue应用中多个组件的共享状态进行集中式的管理读/写也是一种组件间通信的方式且适用于任意组件间通信。Github 地址: https://github.com/vuejs/vuex
2、什么时候使用 Vuex
1.多个组件依赖于同一状态数据 2.来自不同组件的行为需要变更同一状态数据
3、搭建环境
1、创建文件src/store/index.js
//该文件用于创建vuex中最为核心的store// 引入vue核心库
import Vue from vue
//引入vuex
import Vuex from vuex
// 应用Vuex插件
Vuex.usr(Vuex) //准备action-用于响应组件中的动作
const actions{}
//准备mutations-用于操作数据state
const mutations{}
//准备state-用于存储数据
const state {}// 创建并暴露store
export default new Vuex.Store({actions,mutations,state
})2、在mian.js中创建vm时传入store配置项
//引入Vue
import Vue from vue
//引入App
import App from ./App.vue
//关闭Vue的生产提示
Vue.config.productionTip false
//引入插件
import vueResource from vue-resource// 引入store
import store from ./store/index// 使用插件
Vue.use(vueResource)//创建vm
new Vue({el:#app,render: h h(App),store
})4、基本使用
1、初始化数据、配置actions、配置mutations操作文件store.js
//该文件用于创建vuex中最为核心的store// 引入vue核心库
import Vue from vue
//引入vuex
import Vuex from vuex
// 应用Vuex插件
Vuex.usr(Vuex) //准备action-用于响应组件中的动作
const actions{// jia(miniStore,value){// miniStore.commit(JIA,value)// },// jian(miniStore,value){// miniStore.commit(JIAN,value)// },jiaOdd(miniStore,value){if(miniStore.state.sum % 2){miniStore.commit(JIA,value)}},jiaWait(miniStore,value){setTimeout(() {miniStore.commit(JIA,value)}, 500);},
}
//准备mutations-用于操作数据state
const mutations{JIA(state,value){state.sumvalue},JIAN(state,value){state.sum-value}
}
//准备state-用于存储数据
const state {sum:0,//当前和
}// 创建并暴露store
export default new Vuex.Store({actions,mutations,state
})
2、组件中读取vuex中的数据
$store.state.sum3.组件中修改vuex中的数据: $store.dispatch(action中的方法名,数据) 或 $store.commit(mutations中的方法名,数据)备注: 若没有网络请求或其他业务逻辑组件中也可以越过actions即不写dispath直接编写commit 如
templatedivh1当前求和为{{$store.state.sum}}/h1select v-modelnoption :value11/optionoption :value22/optionoption :value33/option/selectbutton clickincrement/buttonbutton clickdecrement-/buttonbutton clickincrementOdd当前求和为奇数时加/buttonbutton clickincrementWait等一等再加/button/div
/template
script
export default {name:Category,date(){return{// sum:0,//当前和n:1,//用户选择的数字}},methods:{increment(){// this.sumthis.n//this.$store.dispatch(jia,this.n)//没有业务逻辑可以dispatch 直接写成this.$store.commit(JIA,n)},decrement(){// this.sum-this.nthis.$store.dispatch(jian,this.n)},incrementOdd(){// if(this.sum % 2){// this.sumthis.n// }this.$store.dispatch(jiaOdd,this.n)},incrementWait(){// setTimeout(() {// this.sumthis.n// }, 500);this.$store.dispatch(jiaWait,this.n)},}
}
/scriptstyle/style5、getters的使用
1.概念:
当state中的数据需要经过加工后再使用时可以使用getters加工。
2.在store.js 中追加getters 配置 ......const getters {bigSum(state){return state.sum * 10}}//创建并暴露storeexport default new Vuex.Store({......getters})3.组件中读取数据:
$store.getters.bigSum如
h3当前求和放大十倍后为{{$store.getters.bigSum}}/h36、四个map方法的使用
1.mapstate方法:
用于帮助我们映射state 中的数据为计算属性
computed:{//借助mapState生成计算属性: sum、schoo1、subject (对象写法)...mapState((sum:sum,school: school,subject:subject}),//借助mapstate生成计算属性: sum、schoo1、subject (数组写法)...mapState([sum,school,subject]),
}2.mapGetters方法:
用于帮助我们映射getters 中的数据为计算属性
computed:{//借助mapGetters生成计算属性。bigSum (对象写法)...mapGetters({bigSum;bigSum}).//借助mapGetters生成计算属性: bigSum (数组写法)...mapGetters([bigSum])
}3.mapActions方法:
用于帮助我们生成与actions 对话的方法即: 包含$store.dispatch(xxx)的函数 methods:{//靠mapActions生成:incrementOdd、incrementWait (对象形式)..mapActions(fincrementOdd:jiaOdd,incrementWait:jiaWait})//靠mapActions生成:incrementOdd、incrementWait (数组形式)...mapActions([jiaOdd,jiawait])}4.mapMutations方法:
用于帮助我们生成与mutations对话的方法即:包含$store,commit(xxx)的函数
methods:(//靠mapActions生成: increment、decrement (对象形式)...mapMutations({increment:JIA,decrement:JIAN}),//靠mapMutations生成:JIA、JIAN (对象形式)...mapMutations([JIA,JIAN]),
}备注: mapActions与mapMutations使用时若需要传递参数需要: 在模板中绑定事件时传递好参数否则参数是事件对象。 如
templatedivh1当前求和为{{sum}}/h1h3当前求和放大10倍为{{bigSum}}/h3h3我在{{school}}学习{{subject}}/h3select v-model.numbernoption value11/optionoption value22/optionoption value33/option/selectbutton clickincrement(n)/buttonbutton clickdecrement(n)-/buttonbutton clickincrementOdd(n)当前求和为奇数再加/buttonbutton clickincrementWait(n)等一等再加/button/div
/templatescriptimport {mapState,mapGetters,mapMutations,mapActions} from vuexexport default {name:Count,data() {return {n:1, //用户选择的数字}},computed:{//靠程序员自己亲自去写计算属性/* sum(){return this.$store.state.sum},school(){return this.$store.state.school},subject(){return this.$store.state.subject}, *///借助mapState生成计算属性从state中读取数据。对象写法// ...mapState({he:sum,xuexiao:school,xueke:subject}),//借助mapState生成计算属性从state中读取数据。数组写法...mapState([sum,school,subject]),/* ******************************************************************** *//* bigSum(){return this.$store.getters.bigSum}, *///借助mapGetters生成计算属性从getters中读取数据。对象写法// ...mapGetters({bigSum:bigSum})//借助mapGetters生成计算属性从getters中读取数据。数组写法...mapGetters([bigSum])},methods: {//程序员亲自写方法/* increment(){this.$store.commit(JIA,this.n)},decrement(){this.$store.commit(JIAN,this.n)}, *///借助mapMutations生成对应的方法方法中会调用commit去联系mutations(对象写法)...mapMutations({increment:JIA,decrement:JIAN}),//借助mapMutations生成对应的方法方法中会调用commit去联系mutations(数组写法)// ...mapMutations([JIA,JIAN]),/* ************************************************* *///程序员亲自写方法/* incrementOdd(){this.$store.dispatch(jiaOdd,this.n)},incrementWait(){this.$store.dispatch(jiaWait,this.n)}, *///借助mapActions生成对应的方法方法中会调用dispatch去联系actions(对象写法)...mapActions({incrementOdd:jiaOdd,incrementWait:jiaWait})//借助mapActions生成对应的方法方法中会调用dispatch去联系actions(数组写法)// ...mapActions([jiaOdd,jiaWait])},mounted() {const x mapState({he:sum,xuexiao:school,xueke:subject})console.log(x)},}
/scriptstyle langcssbutton{margin-left: 5px;}
/style
7.模块化命名空间
1.目的:
让代码更好维护让多种数据分类更加明确
2.修改store.js
const countAbout {namespaced;true,//开启命名空间state:(x:1),mutations:(...}actions:[..},getters: {bigSum(state){return state.sum * 10}}
}const personAbout {namespaced;true,//开启命名空间state:{ ... },mutations: { ...},actions:{ ...}
}
const store new Vuex.Store(modules:{countAbout.personAbout}
})如
第 6 章vue-router路由
1 vue-router 的理解
vue 的一个插件库专门用来实现 SPA 应用
2 对 SPA 应用的理解
单页 Web 应用single page web applicationSPA。整个应用只有一个完整的页面。点击页面中的导航链接不会刷新页面只会做页面的局部更新。数据需要通过 ajax 请求获取。
3 路由的理解
1. 什么是路由?
一个路由就是一组映射关系key - valuekey 为路径, value 可能是 function 或 component
2. 路由分类
1. 后端路由
理解value 是 function, 用于处理客户端提交的请求。工作过程服务器接收到一个请求时, 根据请求路径找到匹配的函数来处理请求, 返回响应数据。
2. 前端路由
理解value 是 component用于展示页面内容。工作过程当浏览器的路径改变时, 对应的组件就会显示。
4 路由的基本使用
1.安装vue-router命令:
npm i vue-router32.应用插件:
Vue.use(VueRouter)如
//引入Vue
import Vue from vue
//引入App
import App from ./App.vue
//关闭Vue的生产提示
Vue.config.productionTip false
//引入vueRouter
import VueRouter from vue-router
//引入路由器
import router from ./router/index//应用插件
Vue.use(VueRouter)//创建vm
new Vue({el:#app,render: h h(App),router:router
})3.编写router配置项:
//该文件专门用于创建整个应用的路由器
import VueRouter from vue-router
//引入组件
import About from /components/About
import Home from ../components/Home//创建并暴露路由器去管理一组一组的路由规则export default new VueRouter({routes:[{path:/about,component:About},{path:/home,component:Home}]
})4.实现切换(active-class可配置高亮样式)
router-link active-classactive to/aboutAbout/router-link5.指定展示位置
router-view/router-view如
templatedivdiv classrowdiv classcol-xs-offset-2 col-xs-8div classpage-headerh2Vue Router Demo/h2/div/div/divdiv classrowdiv classcol-xs-2 col-xs-offset-2div classlist-group!-- 原始html中我们使用a标签实现页面的跳转 --!-- a classlist-group-item active href./about.htmlAbout/aa classlist-group-item href./home.htmlHome/a --!--Vue中借助router-lick标签实现路由的切换 --router-link classlist-group-item active-classactive to/aboutAbout/router-linkrouter-link classlist-group-item active-classactive to/homeHome/router-link/div/divdiv classcol-xs-6div classpaneldiv classpanel-body!-- 指定组件的呈现位置 --router-view/router-view/div/div/div/div/div
/templatescriptexport default {name:App}
/script
style scoped/style6.几个注意点
1.路由组件通常存放在pages 文件夹一般组件通常存放在components 文件夹 2.通过切换“隐藏”了的路由组件默认是被销毁掉的需要的时候再去挂载。 3.每个组件都有自己的 $route 属性里面存储着自己的路由信息 4.整个应用只有一个router可以通过组件的 $router 属性获取到。
5、嵌套多级路由
1.配置路由规则使用children配置项:
routes:[{path:/aboutcomponent :About .},{path : /home,component :Home,children{//通过children配置子级路由{path:news//此处一定不要写: /newscomponent:News}, {path:message’,//此处一定不要写/messagecomponent:Message}}}
]2.跳转 (要写完整路径) :
router-link to/home/newsNews/router-link6、路由的query传参
1、传递参数
ulli v-form in messageList :keym.id!-- 跳转路由并携带query参数to的字符串写法 --!-- router-link :to/home/message/detail?id${m.id}title${m.title}{{m.title}}/router-linknbsp;nbsp; --!-- 跳转路由并携带query参数to的对象写法 --router-link :to{path:/home/message/detail,query:{id:m.id,title:m.title}}/router-link/li
/ul2、接收参数
{{$route.query.id}}
{{$route.query.title}}7、命名路
1.作用:
可以简化路由的跳转
2.如何使用
1.给路由命名 2.简化跳转: 8、路由的params参数
1、配置路由声明接收 params参数 2、传递参数 3、接收参数 9.路由的props配置
作用 让路由组件更方便的收到参数
{name:xiangqing,path:detail/:id,component:Detail,//第一种写法props值为对象该对象中所有的key-value的组合最终都会通过props传给Detail组件// props:{a:900}//第二种写法props值为布尔值布尔值为true则把路由收到的所有params参数通过props传给Detail组件// props:true//第三种写法props值为函数该函数返回的对象中每一组key-value都会通过props传给Detail组件props(route){return {id:route.query.id,title:route.query.title}}
}接收
templateulli消息编号{{id}}/lili消息标题{{title}}/li/ul
/templatescriptexport default {name:Detail,props:[id,title],}
/script10.router-link的replace属性
作用控制路由跳转时操作浏览器历史记录的模式浏览器的历史记录有两种写入方式分别为push和replacepush是追加历史记录replace是替换当前记录。路由跳转时候默认为push如何开启replace模式router-link replace .......News/router-link
11.编程式路由导航 作用不借助router-link 实现路由跳转让路由跳转更加灵活 具体编码 //$router的两个API
this.$router.push({name:xiangqing,params:{id:xxx,title:xxx}
})this.$router.replace({name:xiangqing,params:{id:xxx,title:xxx}
})
this.$router.forward() //前进
this.$router.back() //后退
this.$router.go() //可前进也可后退如
templatedivulli v-form in messageList :keym.id!-- 跳转路由并携带params参数to的字符串写法 --!-- router-link :to/home/message/detail/${m.id}/${m.title}{{m.title}}/router-linknbsp;nbsp; --!-- 跳转路由并携带params参数to的对象写法 --router-link :to{name:xiangqing,query:{id:m.id,title:m.title}}{{m.title}}/router-linkbutton clickpushShow(m)push查看/buttonbutton clickreplaceShow(m)replace查看/button/li/ulhrrouter-view/router-view/div
/templatescriptexport default {name:Message,data() {return {messageList:[{id:001,title:消息001},{id:002,title:消息002},{id:003,title:消息003}]}},methods: {pushShow(m){this.$router.push({name:xiangqing,query:{id:m.id,title:m.title}})},replaceShow(m){this.$router.replace({name:xiangqing,query:{id:m.id,title:m.title}})}},}
/scripttemplatediv classcol-xs-offset-2 col-xs-8div classpage-headerh2Vue Router Demo/h2button clickback后退/buttonbutton clickforward前进/buttonbutton clicktest测试一下go/button/div/div
/templatescriptexport default {name:Banner,methods: {back(){this.$router.back()// console.log(this.$router)},forward(){this.$router.forward()},test(){this.$router.go(3)}},}
/script11、缓存路由组件 作用让不展示的路由组件保持挂载不被销毁。 具体编码 !-- 缓存多个路由组件 --!-- keep-alive :include[News,Message]router-view/router-view/keep-alive--!-- 缓存一个路由组件 --keep-alive include不被销毁的组件名 router-view/router-view/keep-alive12.两个新的生命周期钩子
作用路由组件所独有的两个钩子用于捕获路由组件的激活状态。具体名字 activated路由组件被激活时触发。deactivated路由组件失活时触发。
templateulli :style{opacity}欢迎学习Vue/lilinews001 input typetext/lilinews002 input typetext/lilinews003 input typetext/li/ul
/templatescriptexport default {name:News,data() {return {opacity:1}},//beforeDestroy和mounted对路由不起作用/* beforeDestroy() {console.log(News组件即将被销毁了)clearInterval(this.timer)}, *//* mounted(){this.timer setInterval(() {console.log()this.opacity - 0.01if(this.opacity 0) this.opacity 1},16)}, */activated() {console.log(News组件被激活了)this.timer setInterval(() {console.log()this.opacity - 0.01if(this.opacity 0) this.opacity 1},16)},deactivated() {console.log(News组件失活了)clearInterval(this.timer)},}
/script13、路由守卫
1. 作用
对路由进行权限控制
2. 分类
全局守卫、独享守卫、组件内守卫
3. 全局守卫:
//全局前置守卫初始化时执行、每次路由切换前执行
router.beforeEach((to,from,next){console.log(beforeEach,to,from)if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制if(localStorage.getItem(school) atguigu){ //权限控制的具体规则next() //放行}else{alert(暂无权限查看)// next({name:guanyu})}}else{next() //放行}
})//全局后置守卫初始化时执行、每次路由切换后执行
router.afterEach((to,from){console.log(afterEach,to,from)if(to.meta.title){ document.title to.meta.title //修改网页的title}else{document.title vue_test}
})如
// 该文件专门用于创建整个应用的路由器
import VueRouter from vue-router
//引入组件
import About from ../pages/About
import Home from ../pages/Home
import News from ../pages/News
import Message from ../pages/Message
import Detail from ../pages/Detail//创建并暴露一个路由器
const router new VueRouter({routes:[{name:guanyu,path:/about,component:About,meta:{title:关于}},{name:zhuye,path:/home,component:Home,meta:{title:主页},children:[{name:xinwen,path:news,component:News,meta:{isAuth:true,title:新闻}},{name:xiaoxi,path:message,component:Message,meta:{isAuth:true,title:消息},children:[{name:xiangqing,path:detail,component:Detail,meta:{isAuth:true,title:详情},}]}]}]
})//全局前置路由守卫————初始化的时候被调用、每次路由切换之前被调用
router.beforeEach((to,from,next){console.log(前置路由守卫,to,from)if(to.meta.isAuth){ //判断是否需要鉴权if(localStorage.getItem(school)atguigu){next()}else{alert(学校名不对无权限查看)}}else{next()}
})//全局后置路由守卫————初始化的时候被调用、每次路由切换之后被调用
router.afterEach((to,from){console.log(后置路由守卫,to,from)document.title to.meta.title || 硅谷系统
})export default router
4. 独享守卫:
beforeEnter(to,from,next){console.log(beforeEnter,to,from)if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制if(localStorage.getItem(school) atguigu){next()}else{alert(暂无权限查看)// next({name:guanyu})}}else{next()}
}如
// 该文件专门用于创建整个应用的路由器
import VueRouter from vue-router
//引入组件
import About from ../pages/About
import Home from ../pages/Home
import News from ../pages/News
import Message from ../pages/Message
import Detail from ../pages/Detail//创建并暴露一个路由器
const router new VueRouter({routes:[{name:guanyu,path:/about,component:About,meta:{title:关于}},{name:zhuye,path:/home,component:Home,meta:{title:主页},children:[{name:xinwen,path:news,component:News,meta:{isAuth:true,title:新闻},beforeEnter: (to, from, next) {console.log(独享路由守卫,to,from)if(to.meta.isAuth){ //判断是否需要鉴权if(localStorage.getItem(school)atguigu){next()}else{alert(学校名不对无权限查看)}}else{next()}}},{name:xiaoxi,path:message,component:Message,meta:{isAuth:true,title:消息},children:[{name:xiangqing,path:detail,component:Detail,meta:{isAuth:true,title:详情},}]}]}]
})
export default router
5. 组件内守卫
//进入守卫通过路由规则进入该组件时被调用
beforeRouteEnter (to, from, next) {
},
//离开守卫通过路由规则离开该组件时被调用
beforeRouteLeave (to, from, next) {
}如
templateh2我是About的内容/h2
/templatescriptexport default {name:About,//通过路由规则进入该组件时被调用beforeRouteEnter (to, from, next) {console.log(About--beforeRouteEnter,to,from)if(to.meta.isAuth){ //判断是否需要鉴权if(localStorage.getItem(school)atguigu){next()}else{alert(学校名不对无权限查看)}}else{next()}},//通过路由规则离开该组件时被调用beforeRouteLeave (to, from, next) {console.log(About--beforeRouteLeave,to,from)next()}}
/script14、路由器的两种工作模式
对于一个url来说什么是hash值—— #及其后面的内容就是hash值。hash值不会包含在 HTTP 请求中即hash值不会带给服务器。hash模式 地址中永远带着#号不美观 。若以后将地址通过第三方手机app分享若app校验严格则地址会被标记为不合法。兼容性较好。 history模式 地址干净美观 。兼容性和hash模式相比略差。应用部署上线时需要后端人员支持解决刷新页面服务端404的问题。
如
// 该文件专门用于创建整个应用的路由器
import VueRouter from vue-router
//引入组件
import About from ../pages/About
import Home from ../pages/Home
import News from ../pages/News
import Message from ../pages/Message
import Detail from ../pages/Detail//创建并暴露一个路由器
const router new VueRouter({mode:history,//选择路由模式routes:[]
})export default router
vue3快速上手
一、创建Vue3.0工程
1.使用 vue-cli 创建
官方文档https://cli.vuejs.org/zh/guide/creating-a-project.html#vue-create
## 查看vue/cli版本确保vue/cli版本在4.5.0以上
vue --version
## 安装或者升级你的vue/cli
npm install -g vue/cli
## 创建
vue create vue_test
## 启动
cd vue_test
npm run serve2.使用 vite 创建
官方文档https://v3.cn.vuejs.org/guide/installation.html#vite
vite官网https://vitejs.cn
什么是vite—— 新一代前端构建工具。优势如下 开发环境中无需打包操作可快速的冷启动。轻量快速的热重载HMR。真正的按需编译不再等待整个应用编译完成。 传统构建 与 vite构建对比图
## 创建工程
npm init vite-app project-name
## 进入工程目录
cd project-name
## 安装依赖
npm install
## 运行
npm run dev3.分析工程结构
main.js
//引入的不再是Vue构造函数了引入的是一个名为createApp的工厂函数
import { createApp } from vue
import App from ./App.vue//创建应用实例对象——app(类似于之前Vue2中的vm但app比vm更“轻”)
const app createApp(App)//挂载
app.mount(#app)
二、常用 Composition API
官方文档: https://v3.cn.vuejs.org/guide/composition-api-introduction.html
1.拉开序幕的setup
理解Vue3.0中一个新的配置项值为一个函数。setup是所有Composition API组合API“ 表演的舞台 ”。组件中所用到的数据、方法等等均要配置在setup中。setup函数的两种返回值 若返回一个对象则对象中的属性、方法, 在模板中均可以直接使用。重点关注若返回一个渲染函数则可以自定义渲染内容。了解 注意点 尽量不要与Vue2.x配置混用 Vue2.x配置data、methos、computed…中可以访问到setup中的属性、方法。但在setup中不能访问到Vue2.x配置data、methos、computed…。如果有重名, setup优先。 setup不能是一个async函数因为返回值不再是return的对象, 而是promise, 模板看不到return对象中的属性。后期也可以返回一个Promise实例但需要Suspense和异步组件的配合
2.ref函数
作用: 定义一个响应式的数据语法: const xxx ref(initValue) 创建一个包含响应式数据的引用对象reference对象简称ref对象。JS中操作数据 xxx.value模板中读取数据: 不需要.value直接div{{xxx}}/div 备注 接收的数据可以是基本类型、也可以是对象类型。基本类型的数据响应式依然是靠Object.defineProperty()的get与set完成的。对象类型的数据内部 “ 求助 ” 了Vue3.0中的一个新函数—— reactive函数。
如
templateh1一个人的信息/h1h2姓名{{name}}/h2h2年龄{{age}}/h2h3工作种类{{job.type}}/h3h3工作薪水{{job.salary}}/h3button clickchangeInfo修改人的信息/button
/templatescriptimport {ref} from vueexport default {name: App,setup(){//数据let name ref(张三)let age ref(18)let job ref({type:前端工程师,salary:30K})//修改方法function changeInfo(){name.value 李四age.value 48console.log(job.value)job.value.type UI设计师job.value.salary 60Kconsole.log(name,age)}//返回一个对象常用return {name,age,job,changeInfo}}}
/script3.reactive函数
作用: 定义一个对象类型的响应式数据基本类型不要用它要用ref函数语法const 代理对象 reactive(源对象)接收一个对象或数组返回一个代理对象Proxy的实例对象简称proxy对象reactive定义的响应式数据是“深层次的”。内部基于 ES6 的 Proxy 实现通过代理对象操作源对象内部数据进行操作。 如
templateh1一个人的信息/h1h2姓名{{person.name}}/h2h2年龄{{person.age}}/h2h3工作种类{{person.job.type}}/h3h3工作薪水{{person.job.salary}}/h3h3爱好{{person.hobby}}/h3h3测试的数据c{{person.job.a.b.c}}/h3button clickchangeInfo修改人的信息/button
/templatescriptimport {reactive} from vueexport default {name: App,setup(){//数据let person reactive({name:张三,age:18,job:{type:前端工程师,salary:30K,a:{b:{c:666}}},hobby:[抽烟,喝酒,烫头]})//方法function changeInfo(){person.name 李四person.age 48person.job.type UI设计师person.job.salary 60Kperson.job.a.b.c 999person.hobby[0] 学习}//返回一个对象常用return {person,changeInfo}}}
/script4.Vue3.0中的响应式原理
vue2.x的响应式 实现原理 对象类型通过Object.defineProperty()对属性的读取、修改进行拦截数据劫持。 数组类型通过重写更新数组的一系列方法来实现拦截。对数组的变更方法进行了包裹。 Object.defineProperty(data, count, {get () {}, set () {}
})存在问题 新增属性、删除属性, 界面不会更新。直接通过下标修改数组, 界面不会自动更新。
Vue3.0的响应式 实现原理: 通过Proxy代理: 拦截对象中任意属性的变化, 包括属性值的读写、属性的添加、属性的删除等。 通过Reflect反射: 对源对象的属性进行操作。 MDN文档中描述的Proxy与Reflect Proxyhttps://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy Reflecthttps://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect new Proxy(data, {// 拦截读取属性值get (target, prop) {return Reflect.get(target, prop)},// 拦截设置属性值或添加新属性set (target, prop, value) {return Reflect.set(target, prop, value)},// 拦截删除属性deleteProperty (target, prop) {return Reflect.deleteProperty(target, prop)}
})proxy.name tom 5.reactive对比ref
从定义数据角度对比 ref用来定义基本类型数据。reactive用来定义对象或数组类型数据。备注ref也可以用来定义对象或数组类型数据, 它内部会自动通过reactive转为代理对象。 从原理角度对比 ref通过Object.defineProperty()的get与set来实现响应式数据劫持。reactive通过使用Proxy来实现响应式数据劫持, 并通过Reflect操作源对象内部的数据。 从使用角度对比 ref定义的数据操作数据需要.value读取数据时模板中直接读取不需要.value。reactive定义的数据操作数据与读取数据均不需要.value。
6.setup的两个注意点 setup执行的时机 在beforeCreate之前执行一次this是undefined。 setup的参数 props值为对象包含组件外部传递过来且组件内部声明接收了的属性。context上下文对象 attrs: 值为对象包含组件外部传递过来但没有在props配置中声明的属性, 相当于 this.$attrs。slots: 收到的插槽内容, 相当于 this.$slots。emit: 分发自定义事件的函数, 相当于 this.$emit。
7.计算属性与监视
1.computed函数 与Vue2.x中computed配置功能一致 写法 import {computed} from vuesetup(){//数据let person reactive({firstName:张,lastName:三})//计算属性——简写没有考虑计算属性被修改的情况/* person.fullName computed((){return person.firstName - person.lastName}) *///计算属性——简写let fullName computed((){return person.firstName - person.lastName})//计算属性——完整let fullName computed({get(){return person.firstName - person.lastName},set(value){const nameArr value.split(-)person.firstName nameArr[0]person.lastName nameArr[1]}})
}如
templateh1一个人的信息/h1姓input typetext v-modelperson.firstNamebr名input typetext v-modelperson.lastNamebrspan全名{{person.fullName}}/spanbr全名input typetext v-modelperson.fullName
/templatescriptimport {reactive,computed} from vueexport default {name: Demo,setup(){//数据let person reactive({firstName:张,lastName:三})//计算属性——简写没有考虑计算属性被修改的情况/* person.fullName computed((){return person.firstName - person.lastName}) *///计算属性——完整写法考虑读和写person.fullName computed({get(){return person.firstName - person.lastName},set(value){const nameArr value.split(-)person.firstName nameArr[0]person.lastName nameArr[1]}})//返回一个对象常用return {person}}}
/script
2.watch函数 与Vue2.x中watch配置功能一致 两个小“坑” 监视reactive定义的响应式数据时oldValue无法正确获取、强制开启了深度监视deep配置失效。监视reactive定义的响应式数据中某个属性时deep配置有效。 //情况一监视ref定义的响应式数据
watch(sum,(newValue,oldValue){console.log(sum变化了,newValue,oldValue)
},{immediate:true})//情况二监视多个ref定义的响应式数据
watch([sum,msg],(newValue,oldValue){console.log(sum或msg变化了,newValue,oldValue)
}) /* 情况三监视reactive定义的响应式数据若watch监视的是reactive定义的响应式数据则无法正确获得oldValue若watch监视的是reactive定义的响应式数据则强制开启了深度监视
*/
watch(person,(newValue,oldValue){console.log(person变化了,newValue,oldValue)
},{immediate:true,deep:false}) //此处的deep配置不再奏效//情况四监视reactive定义的响应式数据中的某个属性
watch(()person.job,(newValue,oldValue){console.log(person的job变化了,newValue,oldValue)
},{immediate:true,deep:true}) //情况五监视reactive定义的响应式数据中的某些属性
watch([()person.job,()person.name],(newValue,oldValue){console.log(person的job变化了,newValue,oldValue)
},{immediate:true,deep:true})//特殊情况
watch(()person.job,(newValue,oldValue){console.log(person的job变化了,newValue,oldValue)
},{deep:true}) //此处由于监视的是reactive素定义的对象中的某个属性所以deep配置有效如
templateh2当前求和为{{sum}}/h2button clicksum点我1/buttonhrh2当前的信息为{{msg}}/h2button clickmsg修改信息/buttonhrh2姓名{{person.name}}/h2h2年龄{{person.age}}/h2h2薪资{{person.job.j1.salary}}K/h2button clickperson.name~修改姓名/buttonbutton clickperson.age增长年龄/buttonbutton clickperson.job.j1.salary涨薪/button
/templatescriptimport {ref,reactive,watch} from vueexport default {name: Demo,setup(){//数据let sum ref(0)let msg ref(你好啊)let person reactive({name:张三,age:18,job:{j1:{salary:20}}})//情况一监视ref所定义的一个响应式数据/* watch(sum,(newValue,oldValue){console.log(sum变了,newValue,oldValue)},{immediate:true}) *///情况二监视ref所定义的多个响应式数据/* watch([sum,msg],(newValue,oldValue){console.log(sum或msg变了,newValue,oldValue)},{immediate:true}) *//* 情况三监视reactive所定义的一个响应式数据的全部属性1.注意此处无法正确的获取oldValue2.注意强制开启了深度监视deep配置无效*//* watch(person,(newValue,oldValue){console.log(person变化了,newValue,oldValue)},{deep:false}) //此处的deep配置无效 *///情况四监视reactive所定义的一个响应式数据中的某个属性/* watch(()person.name,(newValue,oldValue){console.log(person的name变化了,newValue,oldValue)}) *///情况五监视reactive所定义的一个响应式数据中的某些属性/* watch([()person.name,()person.age],(newValue,oldValue){console.log(person的name或age变化了,newValue,oldValue)}) *///特殊情况/* watch(()person.job,(newValue,oldValue){console.log(person的job变化了,newValue,oldValue)},{deep:true}) //此处由于监视的是reactive素定义的对象中的某个属性所以deep配置有效 *///返回一个对象常用return {sum,msg,person}}}
/script
3.watchEffect函数 watch的套路是既要指明监视的属性也要指明监视的回调。 watchEffect的套路是不用指明监视哪个属性监视的回调中用到哪个属性那就监视哪个属性。 watchEffect有点像computed 但computed注重的计算出来的值回调函数的返回值所以必须要写返回值。而watchEffect更注重的是过程回调函数的函数体所以不用写返回值。 //watchEffect所指定的回调中用到的数据只要发生变化则直接重新执行回调。
watchEffect((){const x1 sum.valueconst x2 person.ageconsole.log(watchEffect配置的回调执行了)
})如
templateh2当前求和为{{sum}}/h2button clicksum点我1/buttonhrh2当前的信息为{{msg}}/h2button clickmsg修改信息/buttonhrh2姓名{{person.name}}/h2h2年龄{{person.age}}/h2h2薪资{{person.job.j1.salary}}K/h2button clickperson.name~修改姓名/buttonbutton clickperson.age增长年龄/buttonbutton clickperson.job.j1.salary涨薪/button
/templatescriptimport {ref,reactive,watch,watchEffect} from vueexport default {name: Demo,setup(){//数据let sum ref(0)let msg ref(你好啊)let person reactive({name:张三,age:18,job:{j1:{salary:20}}})//监视/* watch(sum,(newValue,oldValue){console.log(sum的值变化了,newValue,oldValue)},{immediate:true}) */watchEffect((){const x1 sum.valueconst x2 person.job.j1.salaryconsole.log(watchEffect所指定的回调执行了)})//返回一个对象常用return {sum,msg,person}}}
/script
8.生命周期 Vue3.0中可以继续使用Vue2.x中的生命周期钩子但有有两个被更名 beforeDestroy改名为 beforeUnmountdestroyed改名为 unmounted Vue3.0也提供了 Composition API 形式的生命周期钩子与Vue2.x中钩子对应关系如下 beforeCreatesetup()createdsetup()beforeMount onBeforeMountmountedonMountedbeforeUpdateonBeforeUpdateupdated onUpdatedbeforeUnmount onBeforeUnmountunmounted onUnmounted
注意组合式API比配置项优先级高 如
templateh2当前求和为{{sum}}/h2button clicksum点我1/button
/templatescriptimport {ref,onBeforeMount,onMounted,onBeforeUpdate,onUpdated,onBeforeUnmount,onUnmounted} from vueexport default {name: Demo,setup(){console.log(---setup---)//数据let sum ref(0)//通过组合式API的形式去使用生命周期钩子onBeforeMount((){console.log(---onBeforeMount---)})onMounted((){console.log(---onMounted---)})onBeforeUpdate((){console.log(---onBeforeUpdate---)})onUpdated((){console.log(---onUpdated---)})onBeforeUnmount((){console.log(---onBeforeUnmount---)})onUnmounted((){console.log(---onUnmounted---)})//返回一个对象常用return {sum}},//通过配置项的形式使用生命周期钩子//#region beforeCreate() {console.log(---beforeCreate---)},created() {console.log(---created---)},beforeMount() {console.log(---beforeMount---)},mounted() {console.log(---mounted---)},beforeUpdate(){console.log(---beforeUpdate---)},updated() {console.log(---updated---)},beforeUnmount() {console.log(---beforeUnmount---)},unmounted() {console.log(---unmounted---)},//#endregion}
/script9.自定义hook函数 什么是hook—— 本质是一个函数把setup函数中使用的Composition API进行了封装。 类似于vue2.x中的mixin。 自定义hook的优势: 复用代码, 让setup中的逻辑更清楚易懂。
如 1、创建usePoint.js
import {reactive,onMounted,onBeforeUnmount} from vue
export default function (){//实现鼠标“打点”相关的数据let point reactive({x:0,y:0})//实现鼠标“打点”相关的方法function savePoint(event){point.x event.pageXpoint.y event.pageYconsole.log(event.pageX,event.pageY)}//实现鼠标“打点”相关的生命周期钩子onMounted((){window.addEventListener(click,savePoint)})onBeforeUnmount((){window.removeEventListener(click,savePoint)})return point
}
2、在需要的地方引入调用即可
templateh2我是Test组件/h2h2当前点击时鼠标的坐标为x{{point.x}}y{{point.y}}/h2
/templatescriptimport usePoint from ../hooks/usePointexport default {name:Test,setup(){const point usePoint()return {point}}}
/script10.toRef 作用创建一个 ref 对象其value值指向另一个对象中的某个属性。 语法const name toRef(person,name) 应用: 要将响应式对象中的某个属性单独提供给外部使用时。 扩展toRefs与toRef功能一致但可以批量创建多个 ref 对象语法toRefs(person)
如
templateh4{{person}}/h4h2姓名{{name}}/h2h2年龄{{age}}/h2h2薪资{{job.j1.salary}}K/h2button clickname~修改姓名/buttonbutton clickage增长年龄/buttonbutton clickjob.j1.salary涨薪/button
/templatescriptimport {ref,reactive,toRef,toRefs} from vueexport default {name: Demo,setup(){//数据let person reactive({name:张三,age:18,job:{j1:{salary:20}}})// const name1 person.name// console.log(%%%,name1)// const name2 toRef(person,name)// console.log(####,name2)const x toRefs(person)console.log(******,x)//返回一个对象常用return {person,// name:toRef(person,name),// age:toRef(person,age),// salary:toRef(person.job.j1,salary),...toRefs(person)}}}
/script
三、其它 Composition API
1.shallowReactive 与 shallowRef shallowReactive只处理对象最外层属性的响应式浅响应式。 shallowRef只处理基本数据类型的响应式, 不进行对象的响应式处理。 什么时候使用? 如果有一个对象数据结构比较深, 但变化时只是外层属性变化 shallowReactive。如果有一个对象数据后续功能不会修改该对象中的属性而是生新的对象来替换 shallowRef。
如
templateh4当前的x.y值是{{x.y}}/h4button clickx{y:888}点我替换x/buttonbutton clickx.y点我x.y/buttonhrh4{{person}}/h4h2姓名{{name}}/h2h2年龄{{age}}/h2h2薪资{{job.j1.salary}}K/h2button clickname~修改姓名/buttonbutton clickage增长年龄/buttonbutton clickjob.j1.salary涨薪/button
/templatescriptimport {ref,reactive,toRef,toRefs,shallowReactive,shallowRef} from vueexport default {name: Demo,setup(){//数据// let person shallowReactive({ //只考虑第一层数据的响应式let person reactive({name:张三,age:18,job:{j1:{salary:20}}})let x shallowRef({y:0})console.log(******,x)//返回一个对象常用return {x,person,...toRefs(person)}}}
/script
2.readonly 与 shallowReadonly
readonly: 让一个响应式数据变为只读的深只读。shallowReadonly让一个响应式数据变为只读的浅只读。应用场景: 不希望数据被修改时。
如
templateh4当前求和为{{sum}}/h4button clicksum点我/buttonhrh2姓名{{name}}/h2h2年龄{{age}}/h2h2薪资{{job.j1.salary}}K/h2button clickname~修改姓名/buttonbutton clickage增长年龄/buttonbutton clickjob.j1.salary涨薪/button
/templatescriptimport {ref,reactive,toRefs,readonly,shallowReadonly} from vueexport default {name: Demo,setup(){//数据let sum ref(0)let person reactive({name:张三,age:18,job:{j1:{salary:20}}})person readonly(person)// person shallowReadonly(person)// sum readonly(sum)// sum shallowReadonly(sum)//返回一个对象常用return {sum,...toRefs(person)}}}
/script3.toRaw 与 markRaw
toRaw 作用将一个由reactive生成的响应式对象转为普通对象。使用场景用于读取响应式对象对应的普通对象对这个普通对象的所有操作不会引起页面更新。 markRaw 作用标记一个对象使其永远不会再成为响应式对象。应用场景: 有些值不应被设置为响应式的例如复杂的第三方类库等。当渲染具有不可变数据源的大列表时跳过响应式转换可以提高性能。
templateh4当前求和为{{sum}}/h4button clicksum点我/buttonhrh2姓名{{name}}/h2h2年龄{{age}}/h2h2薪资{{job.j1.salary}}K/h2h3 v-showperson.car座驾信息{{person.car}}/h3button clickname~修改姓名/buttonbutton clickage增长年龄/buttonbutton clickjob.j1.salary涨薪/buttonbutton clickshowRawPerson输出最原始的person/buttonbutton clickaddCar给人添加一台车/buttonbutton clickperson.car.name!换车名/buttonbutton clickchangePrice换价格/button
/templatescriptimport {ref,reactive,toRefs,toRaw,markRaw} from vueexport default {name: Demo,setup(){//数据let sum ref(0)let person reactive({name:张三,age:18,job:{j1:{salary:20}}})function showRawPerson(){const p toRaw(person)p.ageconsole.log(p)}function addCar(){let car {name:奔驰,price:40}person.car markRaw(car)}function changePrice(){person.car.priceconsole.log(person.car.price)}//返回一个对象常用return {sum,person,...toRefs(person),showRawPerson,addCar,changePrice}}}
/script
4.customRef 作用创建一个自定义的 ref并对其依赖项跟踪和更新触发进行显式控制。 实现防抖效果 templateinput typetext v-modelkeywordh3{{keyword}}/h3/templatescriptimport {ref,customRef} from vueexport default {name:Demo,setup(){// let keyword ref(hello) //使用Vue准备好的内置ref//自定义一个myReffunction myRef(value,delay){let timer//通过customRef去实现自定义return customRef((track,trigger){return{get(){track() //告诉Vue这个value值是需要被“追踪”的return value},set(newValue){clearTimeout(timer)timer setTimeout((){value newValuetrigger() //告诉Vue去更新界面},delay)}}})}let keyword myRef(hello,500) //使用程序员自定义的refreturn {keyword}}}/script5.provide 与 inject 作用实现祖与后代组件间通信 套路父组件有一个 provide 选项来提供数据后代组件有一个 inject 选项来开始使用这些数据 具体写法 祖组件中 setup(){......let car reactive({name:奔驰,price:40万})provide(car,car)......
}后代组件中 setup(props,context){......const car inject(car)return {car}......
}如 App.vue
templatediv classapph3我是App组件祖{{name}}--{{price}}/h3Child//div
/templatescriptimport { reactive,toRefs,provide } from vueimport Child from ./components/Child.vueexport default {name:App,components:{Child},setup(){let car reactive({name:奔驰,price:40W})provide(car,car) //给自己的后代组件传递数据return {...toRefs(car)}}}
/scriptstyle.app{background-color: gray;padding: 10px;}
/styleChild.vue组件
templatediv classchildh3我是Child组件子/h3Son//div
/templatescriptimport {inject} from vueimport Son from ./Son.vueexport default {name:Child,components:{Son},/* setup(){let x inject(car)console.log(x,Child-----)} */}
/scriptstyle.child{background-color: skyblue;padding: 10px;}
/styleSon组件孙
templatediv classsonh3我是Son组件孙{{car.name}}--{{car.price}}/h3/div
/templatescriptimport {inject} from vueexport default {name:Son,setup(){let car inject(car)return {car}}}
/scriptstyle.son{background-color: orange;padding: 10px;}
/style6.响应式数据的判断
isRef: 检查一个值是否为一个 ref 对象isReactive: 检查一个对象是否是由 reactive 创建的响应式代理isReadonly: 检查一个对象是否是由 readonly 创建的只读代理isProxy: 检查一个对象是否是由 reactive 或者 readonly 方法创建的代理
templateh3我是App组件/h3
/templatescriptimport {ref, reactive,toRefs,readonly,isRef,isReactive,isReadonly,isProxy } from vueexport default {name:App,setup(){let car reactive({name:奔驰,price:40W})let sum ref(0)let car2 readonly(car)console.log(isRef(sum))console.log(isReactive(car))console.log(isReadonly(car2))console.log(isProxy(car))console.log(isProxy(sum))return {...toRefs(car)}}}
/scriptstyle.app{background-color: gray;padding: 10px;}
/style四、Composition API 的优势
1.Options API 存在的问题
使用传统OptionsAPI中新增或者修改一个需求就需要分别在datamethodscomputed里修改 。
.Composition API 的优势
我们可以更加优雅的组织我们的代码函数。让相关功能的代码更加有序的组织在一起。但要利用hook函数
五、新的组件
1.Fragment
在Vue2中: 组件必须有一个根标签在Vue3中: 组件可以没有根标签, 内部会将多个标签包含在一个Fragment虚拟元素中好处: 减少标签层级, 减小内存占用
2.Teleport 什么是Teleport—— Teleport 是一种能够将我们的组件html结构移动到指定位置的技术。 teleport to移动位置div v-ifisShow classmaskdiv classdialogh3我是一个弹窗/h3button clickisShow false关闭弹窗/button/div/div
/teleport如
templatedivbutton clickisShow true点我弹个窗/buttonteleport tobodydiv v-ifisShow classmaskdiv classdialogh3我是一个弹窗/h3h4一些内容/h4h4一些内容/h4h4一些内容/h4button clickisShow false关闭弹窗/button/div/div/teleport/div
/templatescriptimport {ref} from vueexport default {name:Dialog,setup(){let isShow ref(false)return {isShow}}}
/scriptstyle.mask{position: absolute;top: 0;bottom: 0;left: 0;right: 0;background-color: rgba(0, 0, 0, 0.5);}.dialog{position: absolute;top: 50%;left: 50%;transform: translate(-50%,-50%);text-align: center;width: 300px;height: 300px;background-color: green;}
/style3.Suspense 等待异步组件时渲染一些额外内容让应用有更好的用户体验 使用步骤 异步引入组件 import {defineAsyncComponent} from vue
const Child defineAsyncComponent(()import(./components/Child.vue))使用Suspense包裹组件并配置好default与 fallback templatediv classapph3我是App组件/h3Suspensetemplate v-slot:defaultChild//templatetemplate v-slot:fallbackh3加载中...../h3/template/Suspense/div
/template如 App.vue
templatediv classapph3我是App组件/h3Suspensetemplate v-slot:defaultChild//templatetemplate v-slot:fallbackh3稍等加载中.../h3/template/Suspense/div
/templatescript// import Child from ./components/Child//静态引入import {defineAsyncComponent} from vue //定义一个异步组件const Child defineAsyncComponent(()import(./components/Child)) //异步引入export default {name:App,components:{Child},}
/scriptstyle.app{background-color: gray;padding: 10px;}
/styleclild.vue
templatediv classchildh3我是Child组件/h3{{sum}}/div
/templatescriptimport {ref} from vueexport default {name:Child,async setup(){let sum ref(0)let p new Promise((resolve,reject){setTimeout((){resolve({sum})},3000)})return await p}}
/scriptstyle.child{background-color: skyblue;padding: 10px;}
/style六、其他
1.全局API的转移 Vue 2.x 有许多全局 API 和配置。 例如注册全局组件、注册全局指令等。 //注册全局组件
Vue.component(MyButton, {data: () ({count: 0}),template: button clickcountClicked {{ count }} times./button
})//注册全局指令
Vue.directive(focus, {inserted: el el.focus()
}Vue3.0中对这些API做出了调整 将全局的API即Vue.xxx调整到应用实例app上 2.x 全局 APIVue3.x 实例 API (app)Vue.config.xxxxapp.config.xxxxVue.config.productionTip移除Vue.componentapp.componentVue.directiveapp.directiveVue.mixinapp.mixinVue.useapp.useVue.prototypeapp.config.globalProperties
2.其他改变 data选项应始终被声明为一个函数。 过度类名的更改 Vue2.x写法 .v-enter,
.v-leave-to {opacity: 0;
}
.v-leave,
.v-enter-to {opacity: 1;
}Vue3.x写法 .v-enter-from,
.v-leave-to {opacity: 0;
}.v-leave-from,
.v-enter-to {opacity: 1;
}移除keyCode作为 v-on 的修饰符同时也不再支持config.keyCodes 移除v-on.native修饰符 父组件中绑定事件 my-componentv-on:closehandleComponentEventv-on:clickhandleNativeClickEvent
/子组件中声明自定义事件 scriptexport default {emits: [close]}
/script移除过滤器filter 过滤器虽然这看起来很方便但它需要一个自定义语法打破大括号内表达式是 “只是 JavaScript” 的假设这不仅有学习成本而且有实现成本建议用方法调用或计算属性去替换过滤器。 …
第三方库
提供第三方库的网站https://www.bootcdn.cn/ 好用的第三方库 dayjs是一个轻量的处理时间和日期的 JavaScript 库和 Moment.js 的 API 设计保持完全一样
浏览器本地存储
webStorage SessionStorage和LocalStorage都称为webStorage 1.存储内容大小一般支持5MB左右 (不同浏览器可能还不一样) 2.浏览器端通过 Window.sessionStorage 和 Window.localStorage 属性来实现本地存储机制。 3.相关API:
1. xxxxxStorage.setItem( key, value);
该方法接受一个键和值作为参数会把键值对添加到存储中如果键名存在则更新其对应的值。
2. xxxxxStorage.getItem(person);
该方法接受一个键名作为参数返回键名对应的值。
3.xxxxxStorage.removeItem( key);
该方法接受一个键名作为参数并把该键名从存储中删除。
4.xxxxxStorage.clear()
该方法会清空存储中的所有数据备注: 1.SessionStorage存储的内容会随着浏览器窗口关闭而消失 2.LocalStorage存储的内容需要手动清除才会消失。 3.xxxxxStorage.getItem(xxx) 如果xxx对应的value获取不到那么getltem的返回值是null。 4.JsoN.parse(nu11)的结果依然是null。