当前位置: 首页 > news >正文

php网站开发百度百科龙岗网站建

php网站开发百度百科,龙岗网站建,软装设计图,安徽网站搭建一、初识vue3 1.vue3简介 2020年9月18日#xff0c;vue3发布3.0版本#xff0c;代号大海贼时代来临#xff0c;One Piece特点#xff1a; 无需构建步骤#xff0c;渐进式增强静态的 HTML在任何页面中作为 Web Components 嵌入单页应用 (SPA)全栈 / 服务端渲染 (SSR)Jams…一、初识vue3 1.vue3简介 2020年9月18日vue3发布3.0版本代号大海贼时代来临One Piece特点 无需构建步骤渐进式增强静态的 HTML在任何页面中作为 Web Components 嵌入单页应用 (SPA)全栈 / 服务端渲染 (SSR)Jamstack / 静态站点生成 (SSG)开发桌面端、移动端、WebGL甚至是命令行终端中的界面 2.Vue3带来了什么 打包大小减少40%初次渲染快55%更新渲染快133%内存减少54% 3.分析目录结构 main.js中的引入在模板中vue3中是可以没有根标签了这也是比较重要的改变应用实例并不只限于一个。createApp API 允许你在同一个页面中创建多个共存的 Vue 应用而且每个应用都拥有自己的用于配置和全局资源的作用域。 //main.js//引入的不再是Vue构造函数了引入的是一个名为createApp的工厂函数 import {createApp} from vue import App from ./App.vue//创建应用实例对象-app(类似于之前vue2中的vm实例但是app比vm更轻) createApp(APP).mount(#app) //卸载就是unmount,卸载就没了 //createApp(APP).unmount(#app)//之前我们是这么写的在vue3里面这一块就不支持了会报错的引入不到 import vue from vue; new Vue({render:(h) h(App) }).$mount(#app)//多个应用实例 const app1 createApp({/* ... */ }) app1.mount(#container-1)const app2 createApp({/* ... */ }) app2.mount(#container-2)安装vue3的开发者工具 方式一 打开chrome应用商店搜索vue 里面有个Vue.js devtools且下面有个角标beta那个就是vue3的开发者工具方式二 离线模式下可以直接将包丢到扩展程序 二、 常用Composition API组合式API 1. setup函数 理解Vue3.0中一个新的额配置项值为一个函数 2.setup是所有Composition API(组合api) “表演的舞台” 组件中所用到的数据、方法等等均要配置在setup中 setup函数的两种返回值: 若返回一个对象则对象中的属性、方法在模板中均可以直接使用。重点关注若返回一个渲染函数则可以自定义渲染内容。 注意点 尽量不要与Vue2.x配置混用 Vue2.x配置data ,methos, computed…中访问到setup中的属性方法但在setup中不能访问到Vue2.x配置data.methos,compued…如果有重名setup优先 setup不能是一个async函数因为返回值不再是return的对象而是promise模板看不到return对象中的属性 import {h} from vue //向下兼容可以写入vue2中的data配置项 module default {name: App,setup(){//数据let name 张三,let age 18,//方法function sayHello(){console.log(name)},//f返回一个对象常用return {name,age,sayHello}//返回一个函数渲染函数//return () {return h(h1,学习)} return () h(h1,学习)}}1.1关于单文件组件script setup/script 每个 *.vue 文件最多可以包含一个 script setup。(不包括一般的 script)这个脚本块将被预处理为组件的 setup() 函数这意味着它将为每一个组件实例都执行。script setup 中的顶层绑定都将自动暴露给模板。script setup 是在单文件组件 (SFC) 中使用组合式 API 的编译时语法糖。当同时使用 SFC 与组合式 API 时该语法是默认推荐。相比于普通的 script 语法它具有更多优势 更少的样板内容更简洁的代码。能够使用纯 TypeScript 声明 props 和自定义事件。这个我下面是有说明的更好的运行时性能 (其模板会被编译成同一作用域内的渲染函数避免了渲染上下文代理对象)。更好的 IDE 类型推导性能 (减少了语言服务器从代码中抽取类型的工作)。 1基本语法 /* 里面的代码会被编译成组件 setup() 函数的内容。这意味着与普通的 script 只在组件被首次引入的时候执行一次不同script setup 中的代码会在每次组件实例被创建的时候执行。*/ script setupconsole.log(hello script setup) /script顶层的绑定会被暴露给模板 当使用 script setup 的时候任何在 script setup 声明的顶层的绑定 (包括变量函数声明以及 import 导入的内容) 都能在模板中直接使用 script setup // 变量 const msg 王二麻子// 函数 function log() {console.log(msg) } /scripttemplatebutton clicklog{{ msg }}/button /templateimport 导入的内容也会以同样的方式暴露。这意味着我们可以在模板表达式中直接使用导入的 action 函数而不需要通过 methods 选项来暴露它 script setup import { say } from ./action /scripttemplatediv{{ say (hello) }}/div /template2响应式 响应式状态需要明确使用响应式 API 来创建。和 setup() 函数的返回值一样ref 在模板中使用的时候会自动解包 script setup import { ref } from vueconst count ref(0) /scripttemplatebutton clickcount{{ count }}/button /template 3使用组件 script setup 范围里的值也能被直接作为自定义组件的标签名使用 /** *这里 MyComponent 应当被理解为像是在引用一个变量。 *如果你使用过 JSX此处的心智模型是类似的。 *其 kebab-case 格式的 my-component 同样能在模板中使用——不过 *强烈建议使用 PascalCase 格式以保持一致性。同时这也有助于区分原生的自定义元素。 */ script setup import MyComponent from ./MyComponent.vue /scripttemplateMyComponent / /template动态组件 /** *由于组件是通过变量引用而不是基于字符串组件名注册的 *在 script setup 中要使用动态组件的时候应该使用*动态的 :is 来绑定 */ script setup import Foo from ./Foo.vue import Bar from ./Bar.vue /scripttemplatecomponent :isFoo /component :issomeCondition ? Foo : Bar / /template递归组件 一个单文件组件可以通过它的文件名被其自己所引用。例如名为 FooBar.vue 的组件可以在其模板中用 FooBar/ 引用它自己。注意这种方式相比于导入的组件优先级更低。如果有具名的导入和组件自身推导的名字冲突了可以为导入的组件添加别名 import { FooBar as FooBarChild } from ./components命名空间组件 可以使用带 . 的组件标签例如 Foo.Bar 来引用嵌套在对象属性中的组件。这在需要从单个文件中导入多个组件的时候非常有用 script setup import * as Form from ./form-components /scripttemplateForm.InputForm.Labellabel/Form.Label/Form.Input /template4使用自定义指令 全局注册的自定义指令将正常工作。本地的自定义指令在 script setup 中不需要显式注册但他们必须遵循 vNameOfDirective 这样的命名规范 script setup const vMyDirective {beforeMount: (el) {// 在元素上做些操作} } /script templateh1 v-my-directiveThis is a Heading/h1 /template如果指令是从别处导入的可以通过重命名来使其符合命名规范 script setup import { myDirective as vMyDirective } from ./MyDirective.js /script5defineProps() 和 defineEmits() 为了在声明 props 和 emits 选项时获得完整的类型推导支持我们可以使用 defineProps 和 defineEmits API它们将自动地在 script setup 中可用 script setup const props defineProps({foo: String }) const emit defineEmits([change, delete]) // setup 代码 /scriptdefineProps 和 defineEmits 都是只能在 script setup 中使用的编译器宏。他们不需要导入且会随着 script setup 的处理过程一同被编译掉。defineProps 接收与 props 选项相同的值defineEmits 接收与 emits 选项相同的值。defineProps 和 defineEmits 在选项传入后会提供恰当的类型推导。传入到 defineProps 和 defineEmits 的选项会从 setup 中提升到模块的作用域。因此传入的选项不能引用在 setup 作用域中声明的局部变量。这样做会引起编译错误。但是它可以引用导入的绑定因为它们也在模块作用域内。 5defineExpose 使用 script setup 的组件是默认关闭的——即通过模板引用或者 $parent 链获取到的组件的公开实例不会暴露任何在 script setup 中声明的绑定。 //可以通过 defineExpose 编译器宏来显式指定在 script setup 组件中要暴露出去的属性 script setup import { ref } from vueconst a 1 const b ref(2) defineExpose({a,b }) /script//当父组件通过模板引用的方式获取到当前组件的实例 //获取到的实例会像这样 { a: number, b: number } (ref 会和在普通实例中一样被自动解包)6useSlots() 和 useAttrs() 在 script setup 使用 slots 和 attrs 的情况应该是相对来说较为罕见的因为可以在模板中直接通过 $slots 和 $attrs 来访问它们。在你的确需要使用它们的罕见场景中可以分别用 useSlots 和 useAttrs 两个辅助函数 script setup import { useSlots, useAttrs } from vueconst slots useSlots() const attrs useAttrs() /script //useSlots 和 useAttrs 是真实的运行时函数它的返回与 setupContext.slots 和 setupContext.attrs 等价。 //它们同样也能在普通的组合式 API 中使用。7与普通的 script 一起使用 script setup 可以和普通的 script 一起使用。普通的 script 在有这些需要的情况下或许会被使用到 声明无法在 script // 普通 script, 在模块作用域下执行 (仅一次) runSideEffectOnce()// 声明额外的选项 export default {inheritAttrs: false,customOptions: {} } /scriptscript setup // 在 setup() 作用域中执行 (对每个实例皆如此) /script8顶层 await script setup 中可以使用顶层 await。结果代码会被编译成 async setup() script setup const post await fetch(/api/post/1).then((r) r.json()) /script // 另外await 的表达式会自动编译成在 await 之后保留当前组件实例上下文的格式。2.ref 函数 作用定义一个响应式的数据语法 const xxx ref(initValue) 创建一个包含响应式数据引用对象reference对象JS中操作数据xxx.value模板中读取数据不需要.value直接 {{xxx}} 备注 接收的数据可以是基本类型、也可以是对象类型基本类型的数据响应式依然靠的是Object.defineProperty()的get和set完成的对象类型的数据 内部”求助“了Vue3.0中的一个新的函数——reactive函数 3.reactive 函数 作用定义一个对象类型的响应式数据基本类型别用他用ref函数语法const 代理对象 reactive(被代理对象)接收一个对象或数组,返回一个代理对象proxy对象reactive定义的响应式数据是”深层次的“内部基于ES6的Proxy实现通过代理对象操作源对象内部数据进行操作 4.Vue3.0中响应式原理 先来看一看vue2的响应式原理 对象类型 通过Object.defineProperty()对属性的读取、修改进行拦截数据劫持数组类型通过重写更新数组的一系列方法来实现拦截。对数组的变更方法进行了包裹 Object.defineProperty( data, count, {get(){},set(){} })//模拟实现一下 let person {name: 张三,age: 15, } let p {} Object.defineProperty( p, name, {configurable: true, //配置这个属性表示可删除的否则delete p.name 是删除不了的 falseget(){//有人读取name属性时调用return person.name},set(value){//有人修改时调用person.name value} })存在问题 1. 新增属性。删除属性。界面不会更新 2. 直接通过下表修改数组界面不会自动更新 vue3的响应式 实现原理: 通过Proxy代理拦截对象中任意属性的变化包括属性值的读写、属性的添加、属性的删除等等。通过Reflect反射对被代理对象的属性进行操作MDN文档中描述的Proxy与Reflect可以参考对应的文档 //模拟vue3中实现响应式 let person {name: 张三,age: 15, } //我们管p叫做代理数据管person叫源数据 const p new Proxy(person,{//target代表的是person这个源对象propName代表读取或者写入的属性名get(target,propName){console.log(有人读取了p上面的propName属性)return target[propName]},//不仅仅是修改调用增加的时候也会调用set(target,propName,value){console.log(有人修改了p身上的${propName}属性我要去更新界面了)target[propName] value},deleteProperty(target,propName){console.log(有人删除了p身上的${propName}属性我要去更新界面了)return delete target[propName]} }) //映射到person上了捕捉到修改那就是响应式啊//vue3底层源码不是我们上面写的那么low实现原理一样但是用了一个新的方式 window.Reflect ![Reflect的写法](https://img-blog.csdnimg.cn/565f96b1be74435cacbc42e06706791d.png)let obj {a: 1,b:2, } //传统的只能通过try catch去捕获异常如果使用这种那么底层源码将会有一堆try catch try{Object.defineProperty( obj, c, {get(){ return 3 },})Object.defineProperty( obj, c, {get(){ return 4 },}) } catch(error) {console.log(error) }//新的方式 通过Reflect反射对象去操作相对来说要舒服一点不会要那么多的try catch const x1 Reflect.defineProperty( obj, c, {get(){ return 3 }, }) const x2 Reflect.defineProperty( obj, c, {get(){ return 3 }, }) //x1,和x2是有返回布尔值的 if(x2){console.log(某某操作成功了) }else {console.log(某某操作失败了) }所以vue3最终的响应式原理如下 let person {name: 张三,age: 15, } //我们管p叫做代理数据管person叫源数据 const p new Proxy(person,{//target代表的是person这个源对象propName代表读取或者写入的属性名get(target,propName){console.log(有人读取了p上面的propName属性)return Reflect.get(target, propName)},//不仅仅是修改调用增加的时候也会调用set(target,propName,value){console.log(有人修改了p身上的${propName}属性我要去更新界面了)Reflect.set(target, propName, value)},deleteProperty(target,propName){console.log(有人删除了p身上的${propName}属性我要去更新界面了)return Reflect.deleteProperty(target,propName) } })5.reactive对比ref 从定义数据角度对比 ref用来定义 基本数据类型reactive用来定义 对象或数组类型数据备注 ref也可以用来定义对象或数组类型数据它内部会自动通过reactive转为代理对象 从原理角度对比 ref通过Object.defineProperty()的get和set来实现响应式数据劫持reactive通过Proxy来实现响应式数据劫持并通过Reflect操作源对象内部的数据 从使用角度对比 ref定义数据操作数据需要 .value ,读取数据时模板中直接读取不需要 .valuereactive 定义的数据 操作数据和读取数据均不需要 .value 5.setup的两个注意点 setup执行的时机 在beforeCreate之前执行一次this是undefinedsetup的参数 props:值为对象包含 组件外部传递过来且组件内部声明接收了属性context上下文对象 attrs: 值为对象包含组件外部传递过来但没有在props配置中声明的属性相当于 this.$attrsslots:收到插槽的内容相当于$slotsemit: 分发自定义事件的函数相当于this.$emit //父组件 script setup // This starter template is using Vue 3 script setup SFCs // Check out https://vuejs.org/api/sfc-script-setup.html#script-setup import HelloWorld from ./components/test3.vue; const hello (val) {console.log(传递的参数是 val); } /scripttemplateimg altVue logo src./assets/logo.png /HelloWorld msg传递吧 hellohellotemplate v-slot:cacaospan是插槽吗/span/templatetemplate v-slot:qwespanmeiyou/span/template/HelloWorld /template //子组件 export default {name: test3,props: [msg],emits:[hello],//这里setup接收两个参数一个是props一个是上下文contextsetup(props,context){/*** props就是父组件传来的值但是他是Porxy类型的对象* Proxy:{msg:传递吧}* 可以当作我们自定义的reactive定义的数据*//*** context是一个对象 包含以下内容* 1.emit触发自定义事件的 * 2.attrs 相当于vue2里面的 $attrs 包含组件外部传递过来但没有在props配置中声明的属性* 3.slots 相当于vue2里面的 $slots* 3.expose 是一个回调函数*/console.log(context.slots);let person reactive({name: 张三,age: 17,})function changeInfo(){context.emit(hello, 666)}//返回对象return {person,changeInfo}//返回渲染函数了解 这个h是个函数//return () h(name,age)} } /script6.计算属性与监视 1computed函数 与vue2.x中的写法一致需要引入computed templateh1一个人的信息/h1div姓 input typetext v-modelperson.firstName名input typetext v-modelperson.lastNamedivspan简名{{person.smallName}}/span brspan全名{{person.fullName}}/span/div/div /template script import { computed,reactive } from vueexport default {name: test4,props: [msg],emits:[hello],setup(){let person reactive({firstName: 张,lastName: 三})//简写形式person.smallName computed((){return person.firstName - person.lastName})//完全形态person.fullName computed({get(){console.log(调用get);return person.firstName * person.lastName},set(value){console.log(调用set);const nameArr value.split(*)person.firstName nameArr[0]person.firstName nameArr[1]},})return {person,}},}/script2watch函数 和computed一样需要引入api有两个小坑 1.监视reactive定义的响应式数据的时候oldValue无法获取到正确的值强制开启了深度监视deep配置无效 2.监视reactive定义的响应式数据中某个属性的时候deep配置有效 具体请看下面代码以及注释 templateh1当前求和为 {{sum}}/h1button clicksum点我1/buttonhrh1当前信息为 {{msg}}/h1button clickmsg! 修改信息/buttonhrh2姓名 {{person.name}}/h2h2年龄 {{person.age}}/h2button clickperson.name ~ 修改姓名/button button clickperson.age增长年龄/button /templatescript//使用setup的注意事项import { watch,ref,reactive } from vueexport default {name: test5,props: [msg],emits:[hello],setup(){let sum ref(0)let msg ref(你好啊)let person reactive({name: 张三,age: 18,job:{salary: 15k},})//由于这里的this是指的是undefined所以使用箭头函数//情况一监视ref所定义的一个响应式数据// watch(sum, (newValue,oldValue){// console.log(新的值,newValue);// console.log(旧的值,oldValue);// })//情况二监视ref所定义的多个响应式数据watch([sum,msg], (newValue,oldValue){console.log(新的值,newValue); //[sum的newValue, msg的newValue]console.log(旧的值,oldValue); //[sum的oldValue, msg的oldValue]},{immediate: true,deep:true}) //这里vue3的deep是有点小问题的可以不用deep隐式强制deep//情况三监视reactive定义的所有响应式数据,//1.此处无法获取正确的oldValuenewValue与oldValue是一致值,且目前无法解决//2.强制开启了深度监视deep配置无效/*** 受到码友热心评论解释 此处附上码友的解释供大家参考* 1. 当你监听一个响应式对象的时候这里的newVal和oldVal是一样的因为他们是同一个对象【引用地址一样】* 即使里面的属性值会发生变化但主体对象引用地址不变。这不是一个bug。要想不一样除非这里把对象都换了* * 2. 当你监听一个响应式对象的时候vue3会隐式的创建一个深层监听即对象里只要有变化就会被调用。* 这也解释了你说的deep配置无效这里是强制的。*/watch(person, (newValue,oldValue){console.log(新的值,newValue); console.log(旧的值,oldValue);})//情况四监视reactive对象中某一个属性的值//注意 这里监视某一个属性的时候可以监听到oldValuewatch(()person.name, (newValue,oldValue){console.log(新的值,newValue); console.log(旧的值,oldValue);})//情况五监视reactive对象中某一些属性的值watch([()person.name,()person.age], (newValue,oldValue){console.log(新的值,newValue); console.log(旧的值,oldValue);})//特殊情况: 监视reactive响应式数据中深层次的对象此时deep的配置奏效了watch(()person.job, (newValue,oldValue){console.log(新的值,newValue); console.log(旧的值,oldValue);},{deep:true}) //此时deep有用return {sum,msg,person,}},} /script3watchEffect函数 watch的套路是既要指明监视的属性也要指明监视的回调watchEffect的套路是不用指明监视哪个属性监视的回调中用到哪个属性那就监视哪个属性watchEffect有点像computed: 但computed注重的计算出来的值回调函数的返回值所以必须要写返回值而watchEffect更注重的是过程回调函数的函数体所以不用写返回值 script//使用setup的注意事项import { ref,reactive,watchEffect } from vueexport default {name: test5,props: [msg],emits:[hello],setup(){let sum ref(0)let msg ref(你好啊)let person reactive({name: 张三,age: 18,job:{salary: 15k},})//用处 如果是比较复杂的业务发票报销等那就不许需要去监听其他依赖只要发生变化立马重新回调//注重逻辑过程你发生改变了我就重新执行回调不用就不执行只执行一次watchEffect((){//这里面你用到了谁就监视谁里面就发生回调const x1 sum.valueconsole.log(我调用了);})return {sum,msg,person,}},} /script7.生命周期函数 templateh1生命周期/h1p当前求和为 {{sum}}/pbutton clicksum加一/button /templatescript//使用setup的注意事项import { ref,reactive,onBeforeMount,onMounted,onBeforeUpdate,onUpdated,onBeforeUnmount,onUnmounted } from vueexport default {name: test7,setup(){let sum ref(0)//通过组合式API的形式去使用生命周期钩子/*** beforeCreate 和 created 这两个生命周期钩子就相当于 setup 所以不需要这两个* * beforeMount onBeforeMount* mounted onMounted* beforeUpdate onBeforeUpdate* updated onUpdated* beforeUnmount onBeforeUnmount* unmounted onUnmounted*/console.log(---setup---);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}},//这种是外层的写法如果想要使用组合式api的话需要放在setup中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---);}} /script8.自定义hook函数 什么是hook函数 本质是一个函数把setup函数中使用的Composition API进行了封装类似于vue2.x中的 mixin自定义hook的优势 复用代码让setup中的逻辑更清楚易懂使用hook实现鼠标打点” 创建文件夹和usePoint.js文件 //usePoint.js import {reactive,onMounted,onBeforeUnmount } from vue function savePoint(){//实现鼠标打点的数据let point reactive({x: null,y: null})//实现鼠标点的方法const savePoint (e){point.x e.pageXpoint.y e.pageY} //实现鼠标打点的生命周期钩子onMounted((){window.addEventListener(click,savePoint)})onBeforeUnmount((){window.removeEventListener(click,savePoint)})return point } export default savePoint//组件test.vuetemplatep当前求和为 {{sum}} /pbutton clicksum加一/buttonhrh2当前点击时候的坐标 x: {{point.x}} y:{{point.y}}/h2/templatescript import { ref } from vue import usePoint from ../hooks/usePoint export default {name: test8,setup(props,context){let sum ref(0)let point usePoint()return {sum,point}} } /script9.toRef 作用 创建一个ref对象其value值指向另一个对象中的某个属性值语法 const name toRef(person, ‘name’)应用要将响应式对象中的某个属性单独提供给外部使用扩展 toRefs与toRef功能一致但是可以批量创建多个ref对象语法 toRefs(person) templateh2姓名 {{name2}}/h2h2年龄 {{person.age}}/h2button clickperson.name ~ 修改姓名/button button clickperson.age增长年龄/button /templatescript//使用setup的注意事项import { reactive, toRef, toRefs } from vueexport default {name: test9,setup(){let person reactive({name: 张三,age: 18,job:{salary: 15k},})//toRefconst name2 toRef(person,name) //第一个参数是对象第二个参数是键名console.log(toRef转变的是,name2); //ref定义的对象//toRefs,批量处理对象的所有属性//const x toRefs(person)//console.log(toRefs转变的是,x); //是一个对象return {person,name2,...toRefs(person)}},} /script三、TypeScript 与组合式 API 1.为组件的 props 标注类型 //场景一 使用script setup script setup langts const props defineProps({foo: { type: String, required: true },bar: Number })props.foo // string props.bar // number | undefined /script//也可以将 props 的类型移入一个单独的接口中 script setup langts interface Props {foo: stringbar?: number } const props definePropsProps() /script //场景二 不使用script setup import { defineComponent } from vueexport default defineComponent({props: {message: String},setup(props) {props.message // -- 类型string} })注意点为了生成正确的运行时代码传给 defineProps() 的泛型参数必须是以下之一 //1.一个类型字面量 defineProps{ /*... */ }()//2.对同一个文件中的一个接口或对象类型字面量的引用 interface Props {/* ... */} definePropsProps()//3.接口或对象字面类型可以包含从其他文件导入的类型引用但是传递给 defineProps 的泛型参数本身不能是一个导入的类型 import { Props } from ./other-file// 不支持 definePropsProps()Props 解构默认值 //当使用基于类型的声明时失去了对 props 定义默认值的能力。通过目前实验性的响应性语法糖来解决 script setup langts interface Props {foo: stringbar?: number }// 对 defineProps() 的响应性解构 // 默认值会被编译为等价的运行时选项 const { foo, bar 100 } definePropsProps() /script2.为组件的 emits 标注类型 //场景一 使用script setup script setup langts const emit defineEmits([change, update]) // 基于类型 const emit defineEmits{(e: change, id: number): void(e: update, value: string): void }() /script//场景二 不使用script setup import { defineComponent } from vueexport default defineComponent({emits: [change],setup(props, { emit }) {emit(change) // -- 类型检查 / 自动补全} })3.为 ref() 标注类型 import { ref } from vue import type { Ref } from vue //1.ref 会根据初始化时的值推导其类型 // 推导出的类型Refnumber const year ref(2020) // TS Error: Type string is not assignable to type number. year.value 2020//2.指定一个更复杂的类型可以通过使用 Ref 这个类型 const year: Refstring | number ref(2020) year.value 2020 // 成功//3.在调用 ref() 时传入一个泛型参数来覆盖默认的推导行为 // 得到的类型Refstring | number const year refstring | number(2020) year.value 2020 // 成功//4.如果你指定了一个泛型参数但没有给出初始值那么最后得到的就将是一个包含 undefined 的联合类型 // 推导得到的类型Refnumber | undefined const n refnumber()4.为reactive() 标注类型 import { reactive } from vue //1.reactive() 也会隐式地从它的参数中推导类型 // 推导得到的类型{ title: string } const book reactive({ title: Vue 3 指引 })//2.要显式地标注一个 reactive 变量的类型我们可以使用接口 interface Book {title: stringyear?: number } const book: Book reactive({ title: Vue 3 指引 })5.为 computed() 标注类型 import { ref, computed } from vue //1.computed() 会自动从其计算函数的返回值上推导出类型 const count ref(0)// 推导得到的类型ComputedRefnumber const double computed(() count.value * 2)// TS Error: Property split does not exist on type number const result double.value.split()//2.通过泛型参数显式指定类型 const double computednumber(() {// 若返回值不是 number 类型则会报错 })6.为事件处理函数标注类型 //在处理原生 DOM 事件时应该为我们传递给事件处理函数的参数正确地标注类型 script setup langts function handleChange(event) {// 没有类型标注时 event 隐式地标注为 any 类型,// 这也会在 tsconfig.json 中配置了 strict: true 或 noImplicitAny: true 时报出一个 TS 错误。console.log(event.target.value) } /scripttemplateinput typetext changehandleChange / /template//因此建议显式地为事件处理函数的参数标注类型,需要显式地强制转换 event 上的属性 function handleChange(event: Event) {console.log((event.target as HTMLInputElement).value) }7.为 provide / inject 标注类型 /* provide 和 inject 通常会在不同的组件中运行。要正确地为注入的值标记类型 Vue 提供了一个 InjectionKey 接口它是一个继承自 Symbol 的泛型类型 可以用来在提供者和消费者之间同步注入值的类型 */ import { provide, inject } from vue import type { InjectionKey } from vueconst key Symbol() as InjectionKeystringprovide(key, foo) // 若提供的是非字符串值会导致错误const foo inject(key) // foo 的类型string | undefined//建议将注入 key 的类型放在一个单独的文件中这样它就可以被多个组件导入。 //当使用字符串注入 key 时注入值的类型是 unknown需要通过泛型参数显式声明 const foo injectstring(foo) // 类型string | undefined//注意注入的值仍然可以是 undefined因为无法保证提供者一定会在运行时 provide 这个值。 //当提供了一个默认值后这个 undefined 类型就可以被移除 const foo injectstring(foo, bar) // 类型string//如果你确定该值将始终被提供则还可以强制转换该值 const foo inject(foo) as string8.为模板引用标注类型 //模板引用需要通过一个显式指定的泛型参数和一个初始值 null 来创建 script setup langts import { ref, onMounted } from vueconst el refHTMLInputElement | null(null)onMounted(() {el.value?.focus() }) /script /**注意为了严格的类型安全有必要在访问 el.value 时使用可选链或类型守卫。这是因为直到组件被挂载前这个 ref 的值都是初始的 null并且在由于 v-if 的行为将引用的元素卸载时也可以被设置为 null。 */ templateinput refel / /template9.为组件模板引用标注类型 //有时你可能需要为一个子组件添加一个模板引用以便调用它公开的方法。举例来说我们有一个 MyModal 子组件它有一个打开模态框的方法 !-- MyModal.vue -- script setup langts import { ref } from vueconst isContentShown ref(false) const open () (isContentShown.value true)defineExpose({open }) /script //为了获取 MyModal 的类型我们首先需要通过 typeof 得到其类型再使用 TypeScript 内置的 InstanceType 工具类型来获取其实例类型 !-- App.vue -- script setup langts import MyModal from ./MyModal.vueconst modal refInstanceTypetypeof MyModal | null(null)const openModal () {modal.value?.open() } /script //注意如果你想在 TypeScript 文件而不是在 Vue SFC 中使用这种技巧需要开启 Volar 的Takeover 模式。四、Vuex与组合式API 组合式API 可以通过调用 useStore 函数来在 setup 钩子函数中访问 store。这与在组件中使用选项式 API 访问 this.$store 是等效的。 import { useStore } from vuexexport default {setup () {const store useStore()} }1.访问 state 和 getter 为了访问 state 和 getter需要创建 computed 引用以保留响应性这与在选项式 API 中创建计算属性等效。 import { computed } from vue import { useStore } from vuexexport default {setup () {const store useStore()return {// 在 computed 函数中访问 statecount: computed(() store.state.count),// 在 computed 函数中访问 getterdouble: computed(() store.getters.double)}} }2.访问 Mutation 和 Action 要使用 mutation 和 action 时只需要在 setup 钩子函数中调用 commit 和 dispatch 函数。 import { useStore } from vuexexport default {setup () {const store useStore()return {// 使用 mutationincrement: () store.commit(increment),// 使用 actionasyncIncrement: () store.dispatch(asyncIncrement)}} }五、 其他的Composition API 1.shallowReactive与shallowRef shallowReactive只处理对象最外层属性的响应式浅响应式只考虑第一层数据的响应式。shallowRef只处理基本数据类型的响应式不进行对象的响应式处理传递基本数据类型的话跟ref没有任何区别ref是可以进行对象的响应式处理的 我们正常的ref创建的数据里面的.value是一个proxy而shallowRef创建的数据 .value里面是一个object数据类型所以不会响应式数据 什么时候使用 如果有一个对象数据结构比较深但变化时只是外层属性变化 shallowReactive如果有一个对象数据后续功能不会修改对象中的属性而是生新的对象来替换 shallowRef 2.readonly与shallowReadonly readonly让一个响应式的数据变成只读的深只读shallowReadonly 让一个响应式数据变成只读的浅只读应用场景不希望数据被修改的时候 scriptimport { reactive,readonly,shallowReadonly } from vueexport default {name: test9,setup(){let person reactive({name: 张三,job:{salary: 20k,}})person readonly(person) //这个时候修改人的信息就不会改变了,所有的都不能改/*** 页面不进行响应式的改变一般存在两种情况* 1.setup里面定义的数据改变了但是vue没有检测到这个时候是不会改变的* 2.setup里面定义的数据压根儿就不让你改这个时候也没法响应式*/person shallowReadonly(person) //只有最外层不能修改是只读的但是job还是可以改的return {person}},} /script3.toRaw与markRaw toRaw 作用:将一个由reactive生成的响应式对象转换为普通对象使用场景用于读取响应式对象对应的普通对象对这个普通对象的所有操作不会引起页面更新 markRaw: 作用标记一个对象使其永远不会再成为响应式对象使用场景 1.有些值不应被设置成响应式的例如复杂的第三方类库等2.当渲染具有不可变数据的大列表时候跳过响应式转换可以提高性能 import {reactive,toRaw,markRaw} from vue setup(){let person reactive({name: 张三,})function showRawPerson(){const p toRaw(person)p.ageconsole.log(p)}function addCar(){let car {name: 奔驰}person.car markRaw(car) //一旦这么做时候他就永远不能当成响应式数据去做了} }4.customRef 创建一个自定义的ref,并对其依赖项跟踪和更新触发进行显示控制实现防抖效果 templateinput typetext v-modelkeywordh3{{keyword}}/h3 /templatescriptimport { customRef, ref } from vueexport default {name: test10,setup(){let timer;//自定义一个ref——名为 myReffunction myRef(value){return customRef((track,trigger){return {get(){console.log(有人读取我的值了要把${value}给他); //两次输出 v-model读取 h3里面的插值语法调了一次track() //追踪一下改变的数据提前跟get商量一下让他认为是有用的return value},set(newValue){console.log(有人把myRef这个容器中数据改了${newValue});clearTimeout(timer)timer setTimeout((){value newValuetrigger() //通知vue去重新解析模板重新再一次调用get()},500)}}})}// let keyword ref(hello) //使用内置提供的reflet keyword myRef(hello) //使用自定义的refreturn {keyword,}},} /script 5.provide与inject 作用实现祖孙组件间的通信套路父组件有一个provide选项提供数据子组件有一个inject选项来开始使用这些数据具体写法 //父组件 script setupimport { ref,reactive,toRefs,provide } from vue; import ChildVue from ./components/Child.vue;let car reactive({name: 奔驰,price: 40w }) provide(car,car) //给自己的后代组件传递数据 const {name, price} toRefs(car) /script templatediv classapph3我是父组件, {{name}}--{{price}}/h3ChildVue/ChildVue/div /template style .app{background-color: gray;padding: 10px;box-sizing: border-box; } /style//子组件 script setup import { ref } from vue/reactivity; import SonVue from ./Son.vue; /scripttemplatediv classapp2h3我是子组件/h3SonVue/SonVue/div /templatestyle .app2{background-color: rgb(82, 150, 214);padding: 10px;box-sizing: border-box; } /style//孙组件 script setupimport { ref,inject } from vue; let car inject(car) //拿到父组件的数据 const {name, price} car /scripttemplatediv classapp3h3我是孙组件/h3p{{name}}-{{price}}/p/div /template style .app3{background-color: rgb(231, 184, 56);padding: 10px;box-sizing: border-box; } /style6.响应式数据的判断 isRef:检查一个值是否为ref对象isReactivce:检查一个对象是否是由reactive创建的响应式代理isReadonly检查一个对象是否由readonly创建的只读代理isProxy:检查一个对象是否由reactive或者readonly方法创建的代理 六、Composition API的优势 1.传统options API存在的问题 使用传统的Options API中新增或者修改一个需求就需要分别在data,methods,computed里面修改 2.Composition API的优势 我们可以更加优雅的组织我们的代码函数让相关功能的代码更加有序的组织在一起 七、新的组件 1.Transition 会在一个元素或组件进入和离开 DOM 时应用动画它是一个内置组件这意味着它在任意别的组件中都可以被使用无需注册。它可以将进入和离开动画应用到通过默认插槽传递给它的元素或组件上。进入或离开可以由以下的条件之一触发 由 v-if 所触发的切换由 v-show 所触发的切换由特殊元素 切换的动态组件 button clickshow !show切换/button Transitionp v-ifshowHelloWord/p /Transition //当一个 Transition 组件中的元素被插入或移除时会发生下面这些事情 /** 1.Vue 会自动检测目标元素是否应用了 CSS 过渡或动画。如果是则一些 CSS 过渡 class 会在适当的时机被添加和移除 2.如果有作为监听器的 JavaScript 钩子这些钩子函数会在适当时机被调用 3.如果没有探测到 CSS 过渡或动画、也没有提供 JavaScript 钩子那么 DOM 的插入、删除操作将在浏览器的下一个动画帧后执行 *///针对CSS 的过渡效果 /** 1.v-enter-from进入动画的起始状态。在元素插入之前添加在元素插入完成后的下一帧移除。 2.v-enter-active进入动画的生效状态。应用于整个进入动画阶段。在元素被插入之前添加在过渡或动画完成之后移除。这个 class 可以被用来定义进入动画的持续时间、延迟与速度曲线类型 3.v-enter-to进入动画的结束状态。在元素插入完成后的下一帧被添加 (也就是 v-enter-from 被移除的同时)在过渡或动画完成之后移除。 4.v-leave-from离开动画的起始状态。在离开过渡效果被触发时立即添加在一帧后被移除 5.v-leave-active离开动画的生效状态。应用于整个离开动画阶段。在离开过渡效果被触发时立即添加在过渡或动画完成之后移除。这个 class 可以被用来定义离开动画的持续时间、延迟与速度曲线类型。 6.v-leave-to离开动画的结束状态。在一个离开动画被触发后的下一帧被添加 (也就是 v-leave-from 被移除的同时)在过渡或动画完成之后移除。 */.v-enter-active, .v-leave-active {transition: opacity 0.5s ease; }.v-enter-from, .v-leave-to {opacity: 0; }2.Fragment 在vue2中组件必须有一个根标签在vue3中组件可以没有根标签内部会将多个标签包含在一个Fragment虚拟元素中好处减少标签层级减少内存占用 3.Teleport 什么是Teleport? —— Teleport是一种能够将我们组件html结构移动到指定位置的技术开发的时候非常有用 //弹窗实现 script setup import { ref,inject } from vue; let isShow ref(false) /scripttemplatedivbutton clickisShow true点我弹窗/buttonteleport tobody //定位到bodydiv classmask v-ifisShowdiv classdialogh4我是一个弹窗/h4h5内容/h5h5内容/h5h5内容/h5button clickisShow false关闭/button/div/div/teleport/div /templatestyle .dialog{width: 300px;height: 300px;text-align: center;position: absolute;top: 50%;left: 50%;transform: translate(-50%,-50%);background-color: blueviolet;margin: 0 auto; } .mask{position: absolute;top: 0;left: 0;bottom: 0;right: 0;background-color: rgba(0, 0, 0, 0.5); } /style4.Suspense script setupimport { defineAsyncComponent } from vue; //引入异步组件 const ChildVue defineAsyncComponent(() import(./components/Child.vue)) //这叫做动态引入 //这种引入叫做异步引入如果app不出来的话那么Child组件也不会引入进来有一个先后顺序// import ChildVue from ./components/Child.vue; //静态引入 // 得等等所有的组件加载完成之后app才会一起出现/*** Suspense这个标签底层就内置了插槽就可以解决异步引入有时候刷新先后出来慢的问题* v-slot:default 表示默认的输出组件* v-slot:fallback 表示如果页面加载的慢了会优先展示这个内容有点像刷新页面的时候数据回来的慢了就加载一会儿 */ /scripttemplatediv classapph3我是父组件/h3Suspensetemplate v-slot:defaultChildVue/ChildVue/templatetemplate v-slot:fallbackh3稍等加载中..../h3/template/Suspense/div /templatestyle .app{background-color: gray;padding: 10px;box-sizing: border-box; } /style /**还有一种方法就是在子组件中setup返回一个promise对象这里之所以可以使用setup返回promise的原因 是: 我们引入的是异步组件且使用了Suspense/Suspense */等待异步组件时渲染一些后备内容获得更好的用户体验 八 新的生命周期钩子 1.常见的生命周期钩子 onMounted() onUpdated() onUnmounted() onBeforeMount() onBeforeUpdate() onBeforeUnmount() onActivated() onDeactivated() onServerPrefetch()2.新的生命周期钩子 //1.onErrorCaptured()注册一个钩子在捕获了后代组件传递的错误时调用。 function onErrorCaptured(callback: ErrorCapturedHook): voidtype ErrorCapturedHook (err: unknown,instance: ComponentPublicInstance | null,info: string ) boolean | void//2.onRenderTracked()注册一个调试钩子当组件渲染过程中追踪到响应式依赖时调用。 function onRenderTracked(callback: DebuggerHook): voidtype DebuggerHook (e: DebuggerEvent) voidtype DebuggerEvent {effect: ReactiveEffecttarget: objecttype: TrackOpTypes /* get | has | iterate */key: any } //3.onRenderTriggered()注册一个调试钩子当响应式依赖的变更触发了组件渲染时调用。 function onRenderTriggered(callback: DebuggerHook): voidtype DebuggerHook (e: DebuggerEvent) voidtype DebuggerEvent {effect: ReactiveEffecttarget: objecttype: TriggerOpTypes /* set | add | delete | clear */key: anynewValue?: anyoldValue?: anyoldTarget?: Mapany, any | Setany } //4.onServerPrefetch():注册一个异步函数在组件实例在服务器上被渲染之前调用。 function onServerPrefetch(callback: () Promiseany): void /** 补充1.如果这个钩子返回了一个 Promise服务端渲染会在渲染该组件前等待该 Promise 完成。2.这个钩子仅会在服务端渲染中执行可以用于执行一些仅存在于服务端的数据抓取过程 *///试例 script setup import { ref, onServerPrefetch, onMounted } from vueconst data ref(null)onServerPrefetch(async () {// 组件作为初始请求的一部分被渲染// 在服务器上预抓取数据因为它比在客户端上更快。data.value await fetchOnServer(/* ... */) })onMounted(async () {if (!data.value) {// 如果数据在挂载时为空值这意味着该组件// 是在客户端动态渲染的。将转而执行// 另一个客户端侧的抓取请求data.value await fetchOnClient(/* ... */)} }) /script九 解决没有this 各种api的方法 在Vue2项目中可以使用this.$router.push等方法进行路由的跳转但是在Vue3的setup函数里并没有this这个概念因此如何使用路由方法 // 在新的vue-router里面尤大加入了一些方法比如这里代替this的useRouter具体使用如下 //引入路由函数 import { useRouter } from vue-router; //使用 setup() {//初始化路由const router useRouter();router.push({path: /});return {}; }在vue2中可以通过this来访问到$refsvue3中由于没有this所以获取不到了但是官网中提供了方法来获取: templateh2 refroot姓名/h2 /template script//使用setup的注意事项import { onMounted, ref } from vueexport default {name: test9,setup(){const root ref(null)onMounted((){console.log(root.value);})return {root}},} /script//第二种方法也可以通过getCurrentInstance来获取 templateh2 refroot姓名/h2 /templatescript//使用setup的注意事项import { onMounted, ref, getCurrentInstance } from vueexport default {name: test9,setup(){)const {proxy} getCurrentInstance()onMounted((){console.log(proxy.$refs.root);})return {}},} /script 关于element在vue3的使用方法没有this.$message等方法解决方案 //关于element在vue3的使用方法没有this.$message等方法解决方案 template!-- 测试组件 --button clickdoLogin登录/button /templatescript import { getCurrentInstance } from vue export default {name: Test,setup () {const instance getCurrentInstance() // vue3提供的方法创建类似于this的实例const doLogin () {instance.proxy.$message({ type: error, text: 登录失败 }) // 类似于this.$message()}return { doLogin }},// 如果想试用this.$message须在mounted钩子函数中setup中没有this实例//但vue3.0中还是建议在setup函数中进行逻辑操作mounted () {this.$message({ type: error, text: 登录失败 })} } /script
http://www.zqtcl.cn/news/464915/

相关文章:

  • ui设计作品网站东莞做网站的网络公司
  • 网站未备案怎么访问做网站图片教程
  • 温州专业营销网站建设网络建设解决方案
  • 滨州网站建设 远洋科技网站需求建设书
  • 知道网站域名怎么联系域名解析不成功是什么意思
  • 武宁网站ui专业设计wordpress评论通知代码6
  • thymeleaf做网站 seo重庆平台网站建设找哪家
  • WordPress子站站群建筑工程网上申请质量安全监督
  • 怎么给网站添加图标山西手机版建站系统哪家好
  • frontpage网页制作视频教程昆明网站建设优化企业
  • 工信部 诚信网站备案公司网络营销方案
  • 网站开发采集工具如何做网站内链优化
  • 在线做英语题的网站揭阳建站服务
  • 网站非法篡改wordpress的知名网站
  • 保定网建站模板uv推广平台
  • 股权分配系统建设网站wordpress mip 模板
  • 网站及其建设的心得体会昆明云南微网站
  • 详情页在线设计网站推荐广州建设网站企业
  • 设计师网站建设哪家网络公司做网站
  • 宣城网站开发专业制注册资金写100万后悔
  • 专业的高密做网站的建公司网站要多久
  • 蚌埠做网站哪家好WordPress强制ssl
  • 1m宽带做网站平台建站
  • 学习做ppt 的网站班会活动设计方案模板
  • 廊坊住房和城乡建设厅网站门户网站开发招标
  • 免费下载网站设计方案wordpress zenmeyong
  • 网站建设与维护相关知识网站建设遵循的规范
  • 网站建设费科目东莞市塘厦镇
  • 网站建设策划书1万字深圳公司网站设计企业
  • 建设企业网站小微asp iis设置网站路径