单屏页面,高度给100%,窗口缩小的情况下顶部内容会不显示
解决办法:给一个最小高度。让一张背景图模糊,不能直接在这个div设置filter:blur(5px),如果直接给设置了背景的div元素设置模糊,那么它里面的字什么的都会变模糊
解决方法:给这个元素加一个伪元素,给这个伪元素使用模糊,这时候会有毛边,只需要定位的时候给left:-10px;right:-10px;top:-10px;bottom:-10px;把设置的宽和高去掉就可以。
<div class="cover">
你好
</div>
.cover{
position: relatvie;
}
.cover::before{
content: '',
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: transparent url('') center center no-repeat;
filter: blur(5px);
background-size: cover
}
或者在最大的父元素里给一个没有子元素的div,设置绝对定位,背景图片和filter
<div class="contain">
<div class="wrapper">
</div>
<div class="main">aaa</div>
</div>
.contain{
width: 400px;
height: 400px;
position: relative;
}
.wrapper{
position: absolute;
left: -10px;
top: -10px;
bottom: -10px;
right: -10px;
display:block;
background: url("http://pkl6kjvxu.bkt.clouddn.com/boy.jpg") no-repeat;
filter: blur(5px);
z-index: -4;
}
- 事件委托的使用
只有可以冒泡的事件才能使用事件委托,因为这样子元素触发事件的时候才能通知父元素(也就是点击子元素会冒泡到父元素),而不支持冒泡的事件就无法使用事件委托
jq的事件委托写法:
//on前面是需要监听的元素的父元素,后面是事件,和需要监听的元素,以及回调
$('ul').on('click','li',(e)=>{
})
4.在循环中有异步事件,如何在循环外获取最后一次异步操作的结果
比如:循环中我需要通过异步操作将每次获得的数据添加到一个数组中,这时我需要在数组外面拿到最后循环结束的结果,如果直接在循环外获取这个数组的值,因为有异步操作所以一开始拿到的会是初始的空数组,而点开这个空数组才是我们的值。
解决方法:
因为是循环也就是会有多个异步事件,所以我们需要创建多个promise,我们需要一开始声明一个promises为空的数组,然后在循环里对这个promises进行push,push里面就是你要进行的异步操作,之所以需要使用多个promise就是因为如果单纯只是使用一个基本类型的promise赋值,每次循环后面的都会把前面的覆盖掉,所以最后通过.then判断的只是最后一次的promise执行的结果,这里通过数组,把所有的promise事件都添加到数组里,然后再循环外使用Promise.all(promises).then()就可以进行循环里所有promise都执行完之后的操作了
let arr = []
let songsId = [1,2,3]
let promises = []
songsId.map(songId=>{
var song = AV.Object.createWithoutData('Song', songId);
// 修改属性
song.set('dependent', this.playlist);
// 保存到云端
promises.push(song.save().then(data=>{
//异步操作直接push进promises数组里
arr.push(data)
}))
})
Promise.all(promises)then(()={
console.log(arr)
})
5.在对dom元素重新渲染的过程中,如果dom元素是一开始就存在于页面中,那么你后期对它里面添加东西,可能不会同步更新,只能刷新页面后才可以,原因是有一部分内容存在了内存里,有一部分留在了dom里,解决方法,将需要添加的元素的父级元素也动态添加,比如通过一个template
如:
<div class="right">
<h1>已有歌单</h1>
<div class="list">
<ul class="list-main"></ul>
</div>
</div>
render(data){
let {playlists} = data
playlists.map(playlist=>{
let {id, name, summary, cover} = playlist
console.log(name)
let $li = $(`
<li>
${name}
<div class="edit">
<button class="edit-playlist">编辑专辑</button>
<button class="edit-songs">编辑歌曲</button>
<button class="delete-playlist">删除专辑</button>
</div>
</li>`).attr('data-playlist-id',id)
this.$el.find('ul').append($li)
})
}
上面的代码,比如你更改了playlists,然后重新调用了一下render,一开始是playlists:[{name:1},{name:2}],后来更改为playlists:[{name:3},{name:2}]后,你会发现dom里显示的还是1,2,但是你在上面打印的name却是最新的3,2,原因就是你的这新的ul留在了内存中,但并未在dom里,解决方法,就是让他的父级ul也动态加载,然后每次重新渲染一下它的父级
<div class="right">
<h1>已有歌单</h1>
<div class="list">
</div>
</div>
template: `
<ul class="list-main"></ul>
`,
render(data){
this.$el.find('.list').html(this.template)
let {playlists} = data
playlists.map(playlist=>{
let {id, name, summary, cover} = playlist
let $li = $(`
<li>
${name}
<div class="edit">
<button class="edit-playlist">编辑专辑</button>
<button class="edit-songs">编辑歌曲</button>
<button class="delete-playlist">删除专辑</button>
</div>
</li>`).attr('data-playlist-id',id)
this.$el.find('ul').append($li)
})
}
6.如何实现单页面里的tab栏每次刷新都定位到点击的位置,而不是初始位置?
实现方法:通过给页面url添加一个#,然后每点击一个tab栏对应的在#后面添加一个参数,每次通过location.hash来获取你#后面的内容,通过后面的参数来对应让哪一个tab里的内容显示
<div class="page tabs">
<ol class="tabs-nav">
<li data-tab-name="page-1"> <div class="text"> 推荐音乐 </div> </li>
<li data-tab-name="page-2"><div class="text">热歌榜</div></li>
<li data-tab-name="page-3"><div class="text">搜索</div></li>
</ol>
<ol class="tab-content noCollapse">
<li class="page-1 active"></li>
<li class="page-2 active"></li>
<li class="page-3 active"></li>
</ol>
</div>
{
let view = {
el: '.tabs',
$el: null,
init(){
this.$el = $(this.el)
}
}
let model = {}
let controller = {
tab: '',
init(view, model){
this.view = view
this.model = model
this.view.init()
this.locationInit()
this.bindEvent()
},
bindEvent(){
this.view.$el.find('.tabs-nav').on('click','li',(e)=>{
let $li = $(e.currentTarget)
$li.addClass('active').siblings().removeClass('active')
let tabName = $li.attr('data-tab-name')
location.href = `index.html#tab=${tabName}`
this.locationInit()
})
},
locationInit(){
let search = location.hash
if(!search){
location.href += `#tab=page-1`
}
this.tab = search.substring(1).split('=')[1]
this.positionTab()
},
positionTab(){
let tabs = ['page-1','page-2','page-3']
tabs.map(tab=>{
if(this.tab === tab){
this.view.$el.find(`.tab-content > .${tab}`).addClass('active')
this.view.$el.find(`.tabs-nav > li[data-tab-name=${tab}]`).addClass('active')
}else{
this.view.$el.find(`.tab-content > .${tab}`).removeClass('active')
this.view.$el.find(`.tabs-nav > li[data-tab-name=${tab}]`).removeClass('active')
}
})
}
}
controller.init(view, model)
}
7.对于事件监听,不管一开始有没有对应的监听事件触发,只要它执行过,后面就只要一触发对应的事件,监听里就会拿到,就像监听一个点击事件一样,一开始页面没有点击事件,但是执行了这个监听事件,后面你每次点击,他都会监听到得到相应的结果,所以在vue中你可以把所有的事件监听都写在created里,只要调用一次就可以
created(){
this.eventBus.$on('new',(data)=>{
console.log(data)
})
}
8.冒泡需要时间,当你给一个点击事件添加一个点击的事件监听的时候,你只需点击一次就可以添加这个事件监听,同时执行它
<div id="app">
<div @click="one">aaa</div>
</div>
<script>
let app = new Vue({
el: '#app',
methods: {
one(){
console.log(0)
document.addEventListener('click',()=>{
console.log(1)
})
}
}
})
</script>
上面的代码,点击一次就可以打印出0和1,具体代码执行是,当你点击aaa触发one,然后开始冒泡,因为冒泡需要时间所以接着就会打印出0,然后给document添加一个监听,之后冒泡到docuemnt,执行了这个事件监听的函数,打印出了1(也就是先监听了docuemnt后冒泡到docuemnt)。所以如果想不让第一次就执行监听里的函数,那么就要给它加一个时间,让它在冒泡后执行
- 当你使用webpack打包的时候如果出现下面的问题
windows用户可将相关的命令在cmd中执行
10.数组的map不会对原数组进行修改会返回一个新的数组,但是如果数组里的每一项是对象的话那么拿到的就还是之前的对象引用,所以你修改这个对象原来的数组里的对象也会跟着变
- 使用transition实现高度变化的过渡效果
不能用 height 。我们可以用 max-height 和 min-height 可以实现同等效果。
.box{
max-height: 120px;
min-height: 120px;
overflow: hidden;
transition: max-height ease-out 0.2s;
}
.box:hover{
max-height: 500px;
transition: max-height ease-in 0.2s;
}
方法1:通过js获取对应显示行数展示的最大字符的数量来让箭头显示和隐藏(对于某些字体来说会有bug)
如上所示,只要下段的 max-height 是一个实际内容不会达到的高度,那就相当于是 auto 了,这里当点击箭头展开全部高度,如果想要实现低于多少行隐藏箭头高度auto的话(这里以三行为例)就需要确定三行显示的高度和显示的字符串长度,比如三行显示65个字符,那么当字符长度小于65就隐藏箭头并且max-height:auto;heigth:auto
<p>
{{str}}
</p>
<i v-if="visibleArrow">箭头</i>
data(){
return {
str: '文字.....'
}
},
computed: {
visibleArrow(){
if(this.str.length < 65) {
return false
}else {
return true
}
}
}
方法2:通过当前内容区域的auto时的高度除以当前区域的行高来判断,如果大于就显示箭头,这里css里展开后的最大高度也是通过js来计算的,会更精确
<strong class="thirty">剧情</strong>
<div v-if="filmInformation.filmIntro">
<p class="justify plots" ref="plot">{{filmInformation.filmIntro}}</p>
<van-icon :name="!plotVisible ? `arrow-down` : `arrow-up`" class="toggle noDisplayArrow" @click="onTogglePlot" ref="arrow"/>
</div>
data () {
plotVisible: false,
maxHeight: 0
}
onTogglePlot () {
if (this.plotVisible) {
// 关闭
this.$refs.plot.style.maxHeight = null
} else {
// 展开
this.$refs.plot.style.maxHeight = this.maxHeight + 'px'
}
this.plotVisible = !this.plotVisible
this.$nextTick(() => {
this.$refs.arrow.classList.remove('noDisplayArrow')
})
},
async getFilmDetails (data) {
// const token = ''
this.$api['movie/getMovieDetails']({ token, ...data }, { noShowLoading: true })
.then(
res => {
this.filmInformation = res.data
this.setPlotMaxHeight()
}
)
},
setPlotMaxHeight () {
this.$nextTick(() => {
if (this.$refs.plot && this.$refs.plot.clientHeight / parseFloat(window.getComputedStyle(this.$refs.plot, null).lineHeight) > 3) {
this.maxHeight = this.$refs.plot.clientHeight
this.$refs.plot.classList.add('maxHeight')
this.$refs.arrow.classList.remove('noDisplayArrow')
}
})
},
.plots {
overflow: hidden;
transition: max-height ease-out .3s;
}
.maxHeight {
max-height: 126px;
}
.noDisplayArrow{
display: none;
}
- eslint报错Do not use 'new' for side effects
解决方法:在使用new的代码前加一行/* eslint-disable no-new */
这句注释可以绕过规则检测
mounted () {
/* eslint-disable no-new */
new Swiper('.swiper-container', {
slidesPerView: this.columns,
spaceBetween: this.spaceBetween
})
}
- 如果dom中使用了v-if或v-show或v-for中,那么在mounted中无法拿到ref里的dom
解决方法: - 在updated中可以获取到(不推荐)
- 在接口数据获取成功后可以获取
<div v-if="filmInformation.filmIntro">
<p class="justify plots" ref="plot">{{filmInformation.filmIntro}}</p>
<van-icon :name="!plotVisible ? `arrow-down` : `arrow-up`" class="toggle noDisplayArrow" @click="onTogglePlot" ref="arrow"/>
</div>
async getFilmDetails (data) {
this.$api['movie/getMovieDetails']({ token, ...data }, { noShowLoading: true })
.then(
res => {
this.filmInformation = res.data
this.setPlotMaxHeight() // 这里可以通过$nextTick拿到ref
}
)
},
setPlotMaxHeight () {
this.$nextTick(() => {
if (this.$refs.plot && this.$refs.plot.clientHeight / parseFloat(window.getComputedStyle(this.$refs.plot, null).lineHeight) > 3) {
this.maxHeight = this.$refs.plot.clientHeight
this.$refs.plot.classList.add('maxHeight')
this.$refs.arrow.classList.remove('noDisplayArrow')
}
})
},
-
对于table绑定的数据里面有弹出层并且弹出层有from表单,表单里有图片上传,如果第一次点击弹窗图片上传后视图可以正确显示,但是关闭弹窗后上传成功视图不显示新的图片的bug
解决方法:不要通过form表单绑定的对象里的属性来绑定上传图片的src和图片数组文件,而要通过一个直接的data属性来绑定,也就是说我们要在点击弹出当前这一列的数据的窗口的时候把对应的form.topicAvatar(这里我在table里绑定的数据就是this.form.topicAvatar)赋值给一个topicAvatar,然后每次图片上传成功后让this.topicAvatar = response.data,然后点击弹窗的保存后this.form.topicAvatar = this.topicAvatar(因为我点保存的时候是把当前的form赋给tableData里对应的一列)
<el-table :data="tableData">
<el-table-column prop="" align="center" label="话题头像">
<template slot-scope="scope">
<img :src="scope.row.topicAvatar" alt="" class="topicAvatar">
</template>
</el-table-column>
</el-table>
<el-dialog :visible.sync="dialogFormVisible">
<el-form :model="form" label-width="96px">
<el-form-item label="话题头像">
<el-upload
class="avatar-uploader"
:action="uploadUrl"
:show-file-list="false"
:on-success="handleAvatarSuccess"
>
<!--直接绑定data下的topicAvatar-->
<div v-if="topicAvatar" :style="{backgroundImage: `url(${topicAvatar})`}" class="avatar" ref="topicAvatar"></div>
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</el-form-item>
<el-table-column label="操作" align="center" width="320">
<template slot-scope="scope">
<el-button @click="onAddOrModifyData(scope.row, scope.$index)">编辑</el-button>
</template>
</el-table-column>
<div slot="footer" class="dialog-footer">
<el-button @click="onCancel">取消</el-button>
<el-button type="primary" @click="onSave">保存</el-button>
</div>
</el-form>
</el-dialog>
<script>
export default {
data(){
return {
tableData: [
{ number: 1, topic: '许志安道歉', imgUrl: [{ url: 'http://cdn.xiaoxiangyoupin.com/dev/upload/manager/600x400_944386372733505536.jpg' }], status: 1, description: '哈哈,我是帅哥',
topicAvatar: 'http://m.imeitou.com/uploads/allimg/171123/3-1G123203S6-50.jpg', address: 'http//wanglifa1995.com', displayGoods: '8',
},
{ number: 1, topic: '王立发帅哥', imgUrl: [], status: 1, description: '你拆',
topicAvatar: '', address: 'http//wanglifa1995.com', displayGoods: '7'
}
],
},
dialogFormVisible: false,
isModify: false,
index: -1,
form: {
topic: '',
description: '',
imgUrl: [],
contents: [
{ content: '' }
],
topicAvatar: ''
},
},
methods: {
onAddOrModifyData(data, index) {
if (data) {
Object.assign(this.form, data)
// 把话题图片的url赋值给直接的data属性
this.topicAvatar = this.form.topicAvatar
this.isModify = true
this.index = index
} else {
this.isModify = false
}
this.dialogFormVisible = true
},
handleAvatarSuccess(response) {
//图片上传成功后把新的url赋值给它
this.topicAvatar = response.data
},
onCancel() {
this.dialogFormVisible = false
},
onSave() {
if (this.isModify) {
// 点保存的时候把对应新的url赋给form里的topicAvatar然后把form赋给当前列
this.form.topicAvatar = this.topicAvatar
this.tableData.splice(this.index, 1, this.form)
} else {
this.tableData.splice(0, 0, this.form)
}
this.dialogFormVisible = false
},
indexMethod(index) {
return (index + 1) + (this.currentPage - 1) * this.pagesize
},
handleSizeChange(val) {
//
},
handleCurrentChange(val) {
//
}
},
}
</script>
总结如果在对象里的某一个属性变了视图没变的情况,如果通过使用$set没有作用,那么直接把这个对象里的属性赋值给一个直接的data下的属性
- 当对数据修改视图不会跟着变得时候,如果使用$set也无效的话,那么就给这个对应html的父级绑定一个key,然后在需要修改的地方对这个key进行++
<el-input v-model="scope.row.prizeNumber" @change="changePrizeNumber"></el-input>
<el-form-item label="奖励号码">
<el-row :gutter="20" :key="count">
<el-col :span="3" v-for="(item,index) in rewardSetting.winningNumbers" :key="index">
<el-input v-model="item.num"></el-input>
</el-col>
</el-row>
data(){
return {
count: 0,
rewardSetting: {winningNumbers: 3}
}
},
methods: {
changePrizeNumber(val) {
const newArrLength = Number(val) - this.rewardSetting.winningNumbers.length
const newArr = []
if (newArrLength && newArrLength > 0) {
for (let i = 0; i < newArrLength; i++) {
newArr.push({ num: '' })
}
}
this.rewardSetting.winningNumbers.push(...newArr)
this.count++
},
}
- ios上拖动事件会触发默认的返回上一页,解决办法:不要对里面的点击事件阻止冒泡,即不要shiyong@click.stop
18.对也横向拖动overflow-x:scroll底部滚动条去除,方法给拖动的内容区域一个高度,超出的隐藏,然后内部高度100%,给一个padding-bottom把滚动条移出去隐藏掉
<div class="topScroll" ref="topWrapper">
<div class="flexBox scrollStar" ref="scrollStar">
<div class="stars flex1">
<div v-for="(item, index) in lists" :key="index" class="stars-item" @click="itemClick(item, index)">
<div class="img-box">
<img v-lazy="item.photo"/>
<span v-if="item.redDot && userToken" class="dot"></span>
</div>
<p class="name">{{item.realName}}</p>
</div>
<div class="stars-item stars-item-more" @click="moreClick">
<img src="../../../assets/yximg1.3/more.png"/>
<p class="name">更多</p>
</div>
</div>
</div>
</div>
mounted () {
this.$refs.scrollStar.onscroll = () => {
this.navScroll = this.$refs.scrollStar.scrollLeft
}
this.$refs.topWrapper.addEventListener('touchmove', (e) => {
e.stopPropagation()
})
},
activated () {
this.$refs.scrollStar.scrollTo(this.navScroll, 0)
},
.topScroll{
width: 100%;
overflow: hidden;
background: #fff;
height: 260px;
}
.scrollStar {
box-sizing: content-box;
width: 100%;
height: 100%;
overflow-x: scroll;
-webkit-overflow-scrolling: touch;
overflow-y: hidden;
padding-bottom: 30px;
}
- 页面代码修改后但是会有之前代码中的操作显示保留下来(或者说你本地代码是好的,但是服务器上的代码一直有问题),这时候如果你页面用了v-if,你就可以考虑是因为v-if缓存了最之前的代码,你可以先切换成v-show来清一下缓存