4月跟着慕客网的视频写了去哪儿网app的小项目,这段时间面试会经常问到其中的知识点,这两天把视频重新浏览了一遍,又有了新的收获,在此做梳理。
width: 100%;
height: 0;
padding-bottom: 50%;
但是如果再放置子元素可能会有问题,这时需要用到子绝父相布局。
<div class="scale"><div class="item">这里是所有子元素的容器</div>
</div>
<style>* {margin: 0;padding: 0;}.scale {width: 100%;padding-bottom: 50%;height: 0;position: relative;}.item {width: 100%;height: 100%;background-color: green;position: absolute;}
</style>
参考文章
scoped及其原理
style标签拥有scoped属性之后,其CSS属性就只能用于当前vue组件,可以使得组件样式互不污染。原理是通过PostCSS给组件中的所有dom添加了一个独一无二的data属性并对应改为属性选择器。
.example[data-v-5558831a] {color: red;
}
<template><div class="example" data-v-5558831a>scoped测试案例</div>
</template>
scoped穿透
用于需要在局部组件中修改第三方组件库样式的情况。
stylus使用>>>,sass和less使用/deep/
外层 >>> 第三方组件 样式
.wrapper >>> .swiper-pagination-bullet-activebackground: #fff外层 /deep/ 第三方组件 {样式
}
.wrapper /deep/ .swiper-pagination-bullet-active{background: #fff;
}
单行文本
overflow: hidden;//超出隐藏
white-space: nowrap;//溢出不换行
text-overflow: ellipsis;//显示省略号
多行文本(针对webkit内核浏览器有效)
<style type="text/css">.test1 {overflow: hidden;text-overflow: ellipsis;display: -webkit-box;-webkit-box-orient: vertical;-webkit-line-clamp: 3;width: 250px;height: 200px;border: 1px solid red;}</style>
<body><div class="test1">测试文字测试文字测试文字测试文字测试文字测试文字测试文字测试文字测试文字测试文字测试文字测试文字</div>
</body>
如果 -webkit-line-clamp改为2则省略号会显示在第二行末尾。
顺便复习浏览器内核
1、IE浏览器内核:Trident内核,也被称为IE内核;
2、Chrome浏览器内核:Chromium内核 → Webkit内核 → Blink内核;
3、Firefox浏览器内核:Gecko内核,也被称Firefox内核;
4、Safari浏览器内核:Webkit内核;
5、Opera浏览器内核:最初是自主研发的Presto内核,后跟随谷歌,从Webkit到Blink内核;
6、360浏览器、猎豹浏览器内核:IE+Chrome双内核;
7、搜狗、遨游、QQ浏览器内核:Trident(兼容模式)+Webkit(高速模式);
8、百度浏览器、世界之窗内核:IE内核;
使用场景:详情页展示景点图片时需要渐隐渐现效果
实现方式:
先定义通用的动画组件fade.vue,结合插槽实现动画
<template><transition><slot></slot></transition>
</template>
<script>
export default {name: 'FadeAnimation'
}
</script>
<style lang="stylus" scoped>.v-enter, .v-leave-toopacity: 0.v-enter-active, .v-leave-activetransition: opacity .5s
</style>
Banner.vue
<fade-animation><commonGallery :imgs="galleryImgs" v-show="showGallery" @close="handleGalleryClose"> </commonGallery>
</fade-animation>
复习
CSS动画
参考文章
.asp
第二篇文章非常详细地阐述了各个属性的取值和含义
keyframes规则定义+绑定到选择器
@keyframes first{from {background:red;}to{background:yellow;}
}
//或者
@keyframes first{0% {background: red;}25% {background: yellow;}50% {background: blue;}100% {background: green;}
}
div{animation: first 5s;//具体属性//animation: first 5s linear 0s 1 alternate both;
}
对于chrome和safari使用-webkit-keyframes和-webkit-animation
对于Firefox使用-moz-keyframes和-moz-animation
对于Opera使用-o-keyframes和-o-animation
JS动画
主要是通过setInerval()和改变函数left、top等值实现
//匀速运动
<style>* {margin: 0;padding: 0;}.content {width: 180px;height: 180px;background: green;position: relative;}
</style>
<body><div class='content'></div><button onclick='move()'>move</button><script>var timer = null;function move() {var content = ElementsByClassName('content')[0];var pos = content.offsetLeft;var end = 500;var speed = 10;timer = setInterval(function () {//减速//var step = (end - pos) * 0.1;//pos += step;pos += 50;content.style.left = pos + 'px';if (pos > end) {clearInterval(timer);}}, 50);}</script>
</body>
参考文章
axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 库,本质上也是对原生XHR的封装,只不过它是Promise的实现版本,符合最新的ES规范,它本身具有以下特征:
1.从浏览器中创建 XMLHttpRequest
2.支持 Promise API
3.客户端支持防止CSRF
4.提供了一些并发请求的接口(重要,方便了很多的操作)
5.从 node.js 创建 http 请求
6.拦截请求和响应
7.转换请求和响应数据
8.取消请求
9.自动转换JSON数据
PS:防止CSRF:就是让你的每个请求都带一个从cookie中拿到的key, 根据浏览器同源策略,假冒的网站是拿不到你cookie中得key的,这样,后台就可以轻松辨别出这个请求是否是用户在假冒网站上的误导输入,从而采取正确的策略。
补充
执行POST请求
axios.post('/user',{firstName:'Fred',lastName:'Flintstone'
}).then(function(response){console.log(response);
}).catch(function(error){console.log(error);
});
执行多个并发请求
同步异步/并发并行的区别 并发不一定并行 但并行一定并发
参考文章
function getUserAccount(){('/user/123');
}
function getUserPermission(){('/user/123/permission');
}
axios.all([getUserAccount(),getUserPermission()])
.then(axios.spread(function(acct,perms){//两个请求都执行完成}
)
);
通过向axios传递相关配置创建请求
//发送POST请求
axios({method:'post',url:'/user/123',data:{firstName:'Fred',lastName:'Flintstone'}
});
以Detail.vue为例
methods: {getDetailInfo () {('/api/detail.json?id=', {params: {id: this.$route.params.id}}).then(this.handleGetDataSucc)},handleGetDataSucc (res) {res = res.dataif ( && res.data) {const data = res.datathis.sightName = data.sightNamethis.bannerImg = data.bannerImgthis.gallaryImgs = data.gallaryImgsthis.list = data.categoryList}}},mounted () {DetailInfo()}
使用场景:城市列表页和主页当前城市需要共享数据。
使用原因:页面共享并且当点击列表任意一项后,当前城市和首页所在城市都要修改,适合使用vuex。
state.js
let defaultCity = '上海'
try {if (localStorage.city) {defaultCity = localStorage.city}
} catch (e) { }
export default { // 全局公用的数据city: defaultCity
}
mutation.js
export default {changeCity (state, city) {state.city = citytry {localStorage.city = city // 存} catch (e) {}}
}
index.js
import Vue from 'vue'
import Vuex from 'vuex'
import state from './state'
import mutations from './mutations'
Vue.use(Vuex)export default new Vuex.Store({state,mutations,getters: {// 类似于computed 需要用state数据计算出新的数据时可以使用 避免数据冗余doubleCity (state) {return state.city + ' ' + state.city}}
})
List.vue
import { mapState, mapMutations } from 'vuex'
methods: {handleCity (city) {this.changeCity(city)this.$router.push('/')},...mapMutations(['changeCity']) // 把名为changeCity的mutation映射到当前组件名为changeCity的方法},computed: {...mapState({ // 映射到当前组件的计算属性currentCity中currentCity: 'city'})}
使用场景:城市列表滑动
使用原因:列表局部滚动,并且better-scroll支持滚动到指定位置,适合实现字母滑动产生列表滑动的效果。
//最外层的div,包括当前城市、热门城市和列表
<div class="list" ref="wrapper"></div>
import Bscroll from 'better-scroll'
mounted () {this.scroll = new Bscroll(this.$refs.wrapper)
}
使用场景:Alphabet组件滑动到某个字母时列表对应显示该字母开头的城市
实现方式:可以采用bus总线,这里采用的是City组件转发
Alphabet.vue
<template><ul class="list"><li class="item" v-for="item of letters" :key="item"@click="handleLetterClick"@touchstart="handleTouchStart"@touchmove="handleTouchMove"@touchend="handleTouchEnd":ref="item">{{ item }}</li></ul>
</template>
<script>
export default {name: 'CityAlphabet',props: {cities: Object},computed: {letters () {const letters = []for (let i in this.cities) {letters.push(i)}return letters}},methods: {handleLetterClick (e) {this.$emit('change', e.target.innerText)}}
}
</script>
City.vue
<city-alphabet :cities="cities" @change="handleLetterChange"></city-alphabet>methods: {handleLetterChange (e) {this.letter = e}}
<city-list :cities="cities" :hotCities="hotCities" :letter="letter"></city-list>
List.vue
props: {cities: Object,hotCities: Array,letter: String
}
watch: {letter () {if (this.letter) {const ele = this.$refs[this.letter][0]this.scroll.scrollToElement(ele)}}
}
参考文章
总结
beforeCreate:vue实例刚被创建,el、data都是undefined
created:el仍为undefined,data有对应的值
beforeMount:el和data都有对应的值,但el还是虚拟dom
mounted:el成功渲染为真实dom
注意
要看到更新区别需要在updated和beforeUpdate钩子中加入log:
console.log(‘真实dom结构:’ + ElementById(‘app’).innerHTML);
因为el更新了,两者区别在于是否渲染到DOM节点中
视频中老师讲这是节流,但是查阅很多文章后发现这种方式是防抖。
参考文章:
防抖与节流
防抖:当持续触发某个事件时,一定时间间隔内没有触发该事件,事件处理函数才会执行一次,如果间隔内再次触发了事件,则重新延时。
例子:持续触发scroll事件时,并不立即执行handle,当1s内没有触发scroll事件时则触发一次handle函数。
function debounce(fn,wait){let timeout=null;return function(){if(timeout!=null){clearTimeout(timeout);}timeout=setTimeout(fn,wait);}
}
function handle(){console.log('debounce');
}
window.addEventListener('scroll',debounce(handle,1000));
节流:当持续触发事件时,有规律地每隔一个时间间隔执行一次事件处理函数。
例子:持续触发scroll事件时,并不立即执行handle函数,每隔1s才会执行一次。
function throttle(fn,wait){var prevw();return function(){var noww();if(now-prev>wait){fn();prevw();}}
}
function handle(){console.log('throttle');
}
window.addEventListener('scroll',throttle(handle,1000));
防抖和节流都可以用于mousemove、scroll、resize、input等事件。
设置一个timer和16ms的时间间隔,如果当前仍有滑动行为,则清除上次的timer。
Alphabet.vue
data () {return {touchStatus: false,startY: 0,timer: null}
},
updated () {this.startY = this.$refs['A'][0].offsetTop},
methods: {handleTouchMove (e) {if (uchStatus) {if (this.timer) {clearTimeout(this.timer)}this.timer = setTimeout(() => {const touchY = e.touches[0].clientY - 66const index = Math.floor((touchY - this.startY) / 20)if (index >= 1 && index <= this.letters.length) {this.$emit('change', this.letters[index - 1])}}, 16)}}}
参考文章
使用场景:从主页切换到城市列表页再返回时希望保存滑动状态
keep-alive介绍
在vue构建的单页面应用(SPA)中,路由模块一般使用vue-router。vue-router不保存被切换组件的状态,进行push或者replace时,旧组件会被销毁,新组建会被新建,走一遍完整的生命周期。
对于某些需求,比如跳转到列表页面,需要保持滚动深度,等返回的时候依然在这个位置,可以使用keep-alive解决。
补充:什么是单页面应用和多页面应用?
参考文章
SPA(单页面应用):公共资源(js、css等)只加载一次,页面跳转是局部刷新,常见PC端网站
MPA(多页面应用):公共资源(js、css等)选择性加载,页面跳转是全部刷新,常见APP端应用
keep-alive使用方式
keep-alive是一个抽象组件,实际不会被渲染在DOM树中,其作用是在内存中缓存组件等到下次渲染依然保持状态,并且触发activated钩子函数。
因为缓存的需要经常出现在页面切换时,所以常常与router-view一起出现。
<keep-alive><router-view/>
</keep-alive>
对于只想渲染某一些页面/组件,可以使用keep-alive组件的属性include/exclude,表示要/不缓存的组件名称(组件定义时的name属性),接收的类型为string/RegExp/string数组。比如
<keep-alive :include="['ListView','DetailView']"><router-view/>
</keep-alive>
如何实现条件缓存
比如在A->B->C中,C->B时保持缓存,A->B时放弃缓存,即B是条件缓存的。解决方案是将B动态地从include数组中增加/删除。
export default{namesapced: true,state:{keepAliveComponents:[]//缓存数组},mutations:{keepAlive(state,component){//防止重复添加!state.keepAliveComponents.includes(component)&&state.keepAliveComponents.push(component)//增加组件},noKeepAlive(state,component){const index=state.keepAliveComponents.indexOf(component)index!=-1&&state.keepAliveComponents.splice(index,1)//删除组件}}
}
//App.vue
<div class="app"><!--传入include数组--><keep-alive :include="keepAliveComponents"><router-view></router-view></keep-alive>
</div>
export default{computed:{...mapState({keepAliveComponents: state=>state.global.keepAliveComponents})}
}
const router=new Router({routes:[{ path:'/A/B',name:'B',component:B,meta:{title:'B页面',keepAlive: true//指定B组件的缓存性}}]
})
router.beforeEach((to,from,next)=>{// 在路由全局钩子beforeEach中,根据keepAlive属性,统一设置页面的缓存性// 作用是每次进入该组件,就将它缓存a.keepAlive){this.$storemit('global/keepAlive',to.name)}
})
export default{name:'B',created(){},beforeRouteLeave(to,from,next){if(to.name!=='C'){this.$storemit('global/noKeepAlive',from.name)}next()}
}
注意: keep-alive中include操作的是组件名,所以每定义一个组件都要显式声明name属性,否则缓存不起作用。而且显式name对devTools有提示作用。
App.vue
<template><div id="app"><keep-alive exclude="Detail"> <!--请求过一次就保存到内存 Detail不被放入缓存 根据不同id请求不同内容--><router-view></router-view></keep-alive></div>
</template>
Home.vue
activated () { // 使用keepAlive后增加的生命周期函数 页面重新显示的时候执行if (this.lastCity !== this.city) {this.lastCity = HomeInfo()}
}
使用场景:控制景点详情页面Header渐隐渐现效果时需要监听scroll事件进行距离判断,改变opacity,在window上添加了scroll监听事件后主页也会受到影响,为此需要解绑全局事件。
实现方式:
activated () {// 全局组件的解绑window.addEventListener('scroll', this.handleScroll)},
deactivated () {// 页面即将被隐藏/替换veEventListener('scroll', this.handleScroll)}
本文发布于:2024-01-29 07:22:47,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170648417013648.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |