【前端面试题目】【3】Vue2
指令、插值
插值、表达式指令、动态属性v-html:会有XSS风险,并且会覆盖子组件模板divp文本插值{{消息}}/ppJS表达式{{标志?'yes':'no'}}/p!--只能是表达式,不能是js语句--p:id='dynamicId'动态属性id/ppv-html='rawHtml'span【注意】使用后v-html,子元素/span/p/div/templatescriptexportdefault{data(){return{message:'hello',flag:true,rawHtml:'b这是粗体/bi这是斜体/i',dynamicId:`id-${Date.now()}`}}}/scriptstyle范围/样式
computed和watch
计算有缓存,如果数据保持不变,watch不会重新计算。如何深度监控?watch监控引用类型,无法获取oldValtemplatedivpnum{{num}}/ppdouble1{{double1}}/pinputv-model='double2'//div/templatescriptexportdefault{data(){return{num:20}},Computed:{double1(){returnthis.num*2},//如果绑定了v-model则需要写getsetdouble2:{get(){returnthis.num*2},set(val){返回这个。num=val/2}}}}/scriptstyle范围/样式
模板divinputv-model='name'/inputv-model='info.city'//div/templatescriptexportdefault{data(){return{name:'Jae',info:{city:'xx'}}},Computed:{},watch:{name(oldVal,val){console.log('watchname',oldVal,val)//Value类型,可以正常获取oldVal和val},info:{handler(oldVal,val){console.log('watchname',oldVal,val)log('watchinfo',oldVal,val)//引用类型,无法获取oldVal。因为指针是相同的,所以它们已经指向新的val},deep:true//深度监控}}}/scriptstylescoped/style
class和style
使用动态属性使用驼峰式模板divp:class='{black:isBack,Yellow:isYellow}'useclass/pp:class='[black,yellow]'useclass(array)/pp:style='styleData'usestyle/p/div/templatescriptexportdefault{data(){return{isBack:true,isYellow:true,black:'black',Yellow:'yellow',styleData:{fontSize:'40px',//驼峰color:'red',backgroundColor:'#ccc'//驼峰式大小写}}}}/scriptstyle作用域/样式
条件渲染
v-ifv-else的用法可以使用变量或===表达式。v-if和v-show之间的区别。v-if和v-showtemplatedivpv-if='type==='a''A/ppv-else-if='type==='b''B/ppv-的使用场景elseother/ppv-show='type==='a''Abyv-show/ppv-show='type==='b''Bbyv-show/p/div/templatescriptexport默认{数据(){return{type:'a'}}}/scriptstyle范围/样式
如果页面需要频繁切换渲染,使用v-show;如果渲染次数不频繁,则使用v-if
循环渲染
如何遍历对象?——您还可以使用v-forkey。v-for和v-if的重要性不能一起使用模板divp遍历数组/pulliv-for='(item,index)inarrList':key='item.id'{{index}}-{{item.id}}-{{item.title}}/li/ulp遍历对象/pulliv-for='(val,key,index)inobjList':key='key'{{index}}-{{key}}-{{val.title}}/li/ul/div/templatescriptexport默认{data(){返回{flag:false,arrList:[{id:'1',title:'title1'},{id:'2',title:'title2'},{id:'3',title:'title3'}],objList:{a:{title33360'title1'},b:{title:'title2'},c:{title:'title3'}}}}}/scriptstyle作用域/样式
事件
事件参数,自定义参数事件修饰符,按键修饰符事件绑定到哪里?templatedivp{{num}}/pbutton@click='handleClickIncre1'+1/buttonbutton@click='handleClickIncre2(2,$event)'+2/button!--事件修饰符--!--阻止点击事件继续传播--a@click.stop='doSomeThing'/a!--提交事件不再重新加载页面--form@submit.pvent='onSubmit'/form!--修饰符串联--a@click.stop.pvent='doSomeThing'/a!--仅修饰符--form@submit.pvent/form!--添加事件监听时使用事件捕获模式,即内部元素触发的事件首先在这里处理,然后交给内部元素进行处理--div@click.capture='doSomeThing'/div!--只有当event.target是当前元素本身时才会触发处理函数,即事件不是从内部元素--div@click.self='doSomeThing'/div!--按键修饰符--button@click.ctrl='onClick'A/button!--仅当按下Ctrl时触发--button@click.ctrl.exact='onClick'A/button!--没有按下系统修饰符时触发--button@click.exact='onClick'A/button/div/templatescriptexportdefault{data(){return{num:0}},method:{handleClickIncre1(event){//原生事件对象console.log('event',event,event.__proto__.constructor)//事件PointerEvent{.}PointerEvent(){[原生代码]}console.log(event.target)//按钮+1/按钮console.log(event.currentTarget)//事件注册到当前元素的this.num++},handleClickIncre2(val,event){console.log(event.target)//按钮+2/按钮this.num=this.num+val}}}/scriptstyle范围/样式
表单
v-model常用表单项textareacheckbox单选修饰符懒惰数字修剪模板divp输入框:{{name}}/pinputtype='text'v-model.trim='name'/inputtype='text'v-model.lazy='name'/inputtype='text'v-model.number='age'/p多行文本:{{desc}}/p!--注意,不是textarea{{desc}}/textarea--textareav-model='desc'/textareapcheckbox{{checked}}/p输入类型='checkbox'v-model='checked'/pmultiplecheckboxes{{checkedNames}}/pinputtype='checkbox'id='jae'value='Jae'v-model='checkedNames'/labelfor='jae'Jae/label输入类型='checkbox'id='tom'value='Tom'v-model='checkNames'/标签for='tom'Tom/label输入类型='checkbox'id='amy'value='Amy'v-model='checkedNames'/标签for='amy'Amy/labelpradio{{性别}}/pinputtype='radio'id='male'value='male'v-model='gender'/labelfor='male'male/labelinputtype='radio'id='female'value='female'v-model='gender'/labelfor='female'female/labelp下拉列表选择{{selected}}/pselectv-model='selected'选项禁用值=''请选择/选项optionA/optionoptionB/optionoptionC/option/selectp下拉列表多选{{selectedList}}/pselectv-model='selectedList'多选项禁用value=''请选择/optionoptionA/optionoptionB/optionoptionC/option/select/div/templatescriptexportdefault{data(){return{name:'Jae',age:22,desc:'hello',checked:true,checkedNames:[],gender:'男性',selected:'',selectedList:[]}}}/scriptstyle范围/样式
props和$emit
代码示例:
!--index.vue--templatediv输入@add='addHandler'/List:list='list'@delete='deleteHandler'//div/templatescriptimport来自'./input'的输入import来自'./List'的列表导出默认{name:'ComponentsDemo',Components:{输入,列表},data(){return{list:[{id:'id-1',title:'Title1'}]}},methods:{addHandler(title){this.list.push({id:`id-${Date.now()}`,title})},deleteHandler(id){console.log(1);this.list=this.list.filter(item=item.id!==id)}}}/script
!--Input.vue--templatedivinputtype='text'v-model='title'按钮@click='addTitle'add/button/div/templatescriptexportdefault{name:'InputName',data(){return{title:''}},methods:{addTitle(){this.$emit('add',this.title)this.title=''}}}/script
!--List.vue--templatedivulliv-for='列表中的项目':key='item.id'{{item.title}}按钮@click='deleteItem(item.id)'删除/按钮/li/ul/div/templatescriptexport默认{name:'ListName',props:{list:{type:数组,default:()=[]}},data(){return{}},methods:{deleteItem(id){this.$发出('删除',id)}}}/脚本
组件间通讯-自定义事件
//event.jsimportVuefrom'vue'exportdefaultnewVue()
!--Input.vue--scriptimporteventfrom'./event'exportdefault{name:'InputName',data(){return{title:''}},methods:{addTitle(){event.$emit('inputAddTitle',this.title)}}}/脚本
!--List.vue--scriptimporteventfrom'./event'exportdefault{Mounted(){event.$on('inputAddTitle',this.addTitleHandler)},beforeDestroy(){//及时销毁,否则就销毁可能会导致内存泄漏event.$off('inputAddTitle',this.addTitleHandler)},methods:{addTitleHandler(title){console.log('发出的输入组件
:',title)}}}[xss_clean]
组件生命周期1)单个组件
挂载阶段更新阶段销毁阶段
2)父子组件
参考上方《prop和$emit》中的代码示例:created(){console.log('index.vuecreated')},mounted(){console.log('index.vuemounted')}
created(){console.log('List.vuecreated')},mounted(){console.log('List.vuemounted')}
输出为:
index.vuecreatedList.vuecreatedList.vuemountedindex.vuemounted
即:父组件比子组件先创建,但是父组件要等子组件渲染完才能渲染
{{text}}
[xss_clean]exportdefault{model:{prop:'text',//对应props中的textevent:'change'},props:{text:{type:String,default:''}}}[xss_clean]
$nextTickVue是异步渲染data改变之后,DOM不会立刻渲染$nextTick会在DOM渲染之后被触发,以获取最新DOM节点代码示例:
[xss_clean]exportdefault{name:'NextTick',data(){return{list:[1,2,3]}},methods:{add(){this.list.push(`${Date.now()}`)this.list.push(`${Date.now()}`)this.list.push(`${Date.now()}`)constulEle=this.$refs.ul//获取DOM元素console.log(ulEle.childNodes.length)}}}[xss_clean]
可以看出这个输出结果不太对,一开始是3个,点击添加后添加了3个,怎么输出长度还是3呢?这就是因为此时输出的DOM节点还是上一次的,还未更新,如果需要得到正常的结果,就需要加上$nextTick确保DOM渲染完成:
this.$nextTick(()=>{constulEle=this.$refs.ulconsole.log(ulEle.childNodes.length)})
slot基本使用代码示例:
[xss_clean]importSlotDemofrom'./SlotDemo.vue'exportdefault{name:'AdvancedUse',components:{SlotDemo},data(){return{website:{url:'',title:'搜索引擎',subTitle:'比百度好用的搜索引擎'}}}}[xss_clean]
[xss_clean]exportdefault{name:'SlotDemo',props:{url:{type:String,defalut:''}},data(){return{}}}[xss_clean]
如果将index.vue中SlotDemo组件修改一下:
作用域插槽代码示例:
[xss_clean]importScopedSlotDemofrom'./ScopedSlotDemo.vue'exportdefault{name:'AdvancedUse',components:{ScopedSlotDemo},data(){return{}}}[xss_clean]
[xss_clean]exportdefault{props:{url:{type:String,defalut:''}},data(){return{website:{url:'',title:'某搜索引擎',subTitle:'比bing不好用的搜索引擎'}}}}[xss_clean]
在父组件中的插槽接收即可:
[xss_clean]importScopedSlotDemofrom'./ScopedSlotDemo.vue'exportdefault{name:'AdvancedUse',components:{ScopedSlotDemo},data(){return{website:{url:'',title:'搜索引擎',subTitle:'比百度好用的搜索引擎'}}}}[xss_clean]
具名插槽
将插入mainslot中,即默认的未命名的slot将插入headerslot中
将插入footerslot中
动态、异步组件动态组件:is="componentName"用法需要根据数据,动态渲染的场景。即组件类型不确定[xss_clean]importNextTickfrom'./NextTick.vue'exportdefault{name:'AdvancedUse',components:{NextTick},data(){return{componentName:'NextTick'}}}[xss_clean]
异步组件import()函数按需加载,异步加载大组件[xss_clean]//importNextTickfrom'./NextTick.vue'不要同步引进来exportdefault{name:'AdvancedUse',components:{NextTick:()=>import('../components/NextTick')//动态引入},data(){return{showCom:false}}}[xss_clean]
keep-alive缓存组件频繁切换,不需要重复渲染Vue常见性能优化[xss_clean]importkeepAliveStateAfrom'./keepAliveStateA'importkeepAliveStateBfrom'./keepAliveStateB'importkeepAliveStateCfrom'./keepAliveStateC'exportdefault{name:'KeepAlive',components:{keepAliveStateA,keepAliveStateB,keepAliveStateC},data(){return{state:'A'}},methods:{changeState(state){this.state=state}}}[xss_clean]
stateA[xss_clean]exportdefault{data(){return{}},computed:{},watch:{},created(){},mounted(){console.log('Amounted')},destroyed(){console.log('Adestroyed')},}[xss_clean]
stateB[xss_clean]exportdefault{data(){return{}},computed:{},watch:{},created(){},mounted(){console.log('Bmounted')},destroyed(){console.log('Bdestroyed')},}[xss_clean]
stateC[xss_clean]exportdefault{data(){return{}},computed:{},watch:{},created(){},mounted(){console.log('Cmounted')},destroyed(){console.log('Cdestroyed')},}[xss_clean]
如果不需要每次切换的时候都销毁组件,该怎么做呢?使用keep-alive:
[xss_clean]
mixin多个组件有相同的逻辑,抽离出来mixin并不是完美的解决方案,会有一些问题Vue3提出的CompositionAPI旨在解决这些问题 {{name}}{{age}}{{city}}[xss_clean]importmyMixinfrom'./mixin'exportdefault{mixins:[myMixin],//可添加多个data(){return{name:'Jae',age:22}},mounted(){console.log('indexmounted')},}[xss_clean]
//mixin.jsexportdefault{data(){return{city:'XXX'}},mounted(){console.log('mixinmounted')},methods:{showName(){console.log(this.name)}}}
mixin的问题
变量来源不明确,不利于阅读多mixin可能造成命名冲突mixin和组件可能出现多对多的关系,复杂度较高
exportdefaultnewVueRouter({routes:[{path:'/',component:()=>import('./../components/home')}]})
大家好,今天小编关注到一个比较有意思的话题,就是关于哪个机构培训cisp好的问题,于是小编就整理了1个相关介绍哪个机构培训cisp好的解答,让我们一起看看吧。c…
大家好,今天小编关注到一个比较有意思的话题,就是关于以色列印度培训机构的问题,于是小编就整理了4个相关介绍以色列印度培训机构的解答,让我们一起看看吧。亚训有哪些…
端午节期间,我们整理了仿天猫H5APP项目vue.js+expss+mongo效果源码源码太多,点击放到github上遇到的问题连接mongodb数据库多个集合…
大家好,今天小编关注到一个比较有意思的话题,就是关于cisp培训机构名单上海的问题,于是小编就整理了1个相关介绍cisp培训机构名单上海的解答,让我们一起看看吧…
PromisePromise是什么?功能:支持链式调用,解决回调地狱问题抽象表达:Promise是一项新技术Promise是JS异步编程的新解决方案,旧的解决方…
2024-10-23 15:00:05
2024-10-23 10:48:05
2024-10-23 08:48:12
2024-10-23 06:36:10
2024-10-23 04:48:07
大家好,今天小编关注到一个比较有意思的话题,就是关于电脑培训有时间要求吗的问题,…
大家好,今天小编关注到一个比较有意思的话题,就是关于新手学电脑选啥电脑好的问题,…