使用fastclick包减少移动端触动div元素时的3ms延迟
import fastclick from 'fastclick';
fastclick.attach(document.body);
图片懒加载
//使用vue-lazyload第三方插件
npm i vue-lazyload -s
//main.js
import vueLazyload from 'vue-lazyload'
Vue.use(vueLazyload)
抽离普通组件
在移动端中像banner图,滑动组件和加载组件等这些基础组件可以抽离为子组件。利用props和slot将父组件中的数据和模板传递给子组件。
<div>
<slot><slot> //子组件中使用slot标签,可以将父组件中把子组件包裹的标签传递给子组件
<div>
//子组件
<script>
export default{
props:{
data:'',
}
}
</script>
//父组件
<子组件 :data='123'></子组件> //如此就将父组件的data相对于的传给了子组件中props的data中。
重复性的数据聚合可以另外封装一个类
//这个类把繁琐的avatar聚合过程封装成了类
export default class Singer {
constructor({id, name}) {
this.id = id
this.name = name
this.avatar = `https://y.gtimg.cn/music/photo_new/T001R300x300M000${id}.jpg?max_age=2592000`
}
}
//类中的构造函数需要传两个参数
var singer = new Siner({
name:'123',
id:'123'
})
eslint下的paops的array属性
其中的default如果设置为[]会报错,需要()=>[]才不会报错
es6的sort和map方法
// 3.将字母用sort方法,将title的charcodeat进行比较排序
ret.sort((a, b) => {
return a.title.charCodeAt(0) - b.title.charCodeAt(0)
})
//map方法就是将本数组进行遍历修改后赋值给新数组
shortcutList() {
return this.data.map((group) => {
return group.title.substr(0, 1)
})
}
dom的attribute方法
是在dom元素中添加和获取属性的值,如id type class name等等属性,也可以自定义属性名
function getData(el, name, val) {
const prefix = 'data-'
name = prefix + name //自定义属性名
if (val) {
return el.setAttribute(name, val) //在el的dom元素添加设置name属性值val
} else {
return el.getAttribute(name) //获取el的dom元素值
}
}
vue数据的响应
在vue的data,props和computed等属性中创建的变量都会自动创建get,set等方法来监听数据的变化,来达到数据的响应。如果有些数据不需要监听,可以在created属性中创建。
created(){
this.message={} //这样就创建了一个message变量,但不会被监听
}
右侧导航与主体导航的联动
1.首先我们需要实时的检测滚动到的位置
// 可以使用bscroll插件提供的listenscroll方法监听所处的位置
if (this.listenScroll) {
let me = this
this.scroll.on('scroll', (pos) => {
me.$emit('scroll', pos)
})
}
//使用emit派发一个事件给父组件,父组件接收
scroll(pos) {
this.scrollY = pos.y //讲y位置传给父组件scrolly值
},
2.将主体的每个导航的位置保存为数组
_calculateHeight() {
this.listHeight = []
let height = 0
this.listHeight.push(height)
let list = this.$refs.listGroup
for (let i = 0; i < list.length; i++) {
height += list[i].clientHeight
this.listHeight.push(height)
}
}
3.使用watch监听滚动的位置跟主体位置数组的区间[i,i+1)进行比较,计算出所处的区间
watch: {
data() {
setTimeout(() => {
this._calculateHeight()
}, 20)
},
//鉴定scrollY的变化
scrollY(newY) {
const listHeight = this.listHeight
// 拉到最顶部的情况
if (newY > 0) {
this.currentIndex = 0
}
// 在中间部分的情况
for (let i = 0; i < listHeight.length - 1; i++) {
let height1 = listHeight[i]
let height2 = listHeight[i + 1]
if (!height2 || (-newY >= height1 && -newY < height2)) {
this.currentIndex = i
// console.log(this.currentIndex)
return
}
}
// 最底部
this.currentIndex = listHeight.length - 2
}
}
4.将右侧导航进行高亮
//判断位置,动态添加current样式
:class="{'current':index == currentIndex}"
vuex
//vuex的常用配置(index.js,state.js,mutations.js,mutation-type.js,getters.js,actions,js)
//vuex提供了许多语法糖,map系列(mapmutation,mapgetters,map...)
//解构赋值出mapMutation方法,进行存数据操作
import {mapMutations} from 'vuex'
methods:{
其他的方法(singer){
this.setSinger(singer)
},
...mapMutations({
setSinger: 'SET_SINGER' //对mutations的一个映射
})
//这样就可以在其他方法中用this.setSinger使用mutation中的SET_SINGER方法
//等同于使用this.$store.commit(SET_SINGER,singer)
}
//解构赋值出mapGetters方法,进行取数据操作
import {mapGetters} from 'vuex'
computed:{
...mapGetters([
'singer' //将getters的singer映射挂载到vue实例中
]),
created(){
console.log(this.singer) //就可以使用this.singer取到getter中singer的映射了
}
}
promise
//promise的用法,先新建一个promise方法,将异步方法放进里面,resolve出你要的值,这里axios是一个异步方法
function getSongUrl(id) {
return new Promise((resolve, reject) => {
axios.get('/song/url?id=' + id).then(res => {
// console.log(res.data.data[0].url)
resolve(res.data.data[0].url)
})
})
}
//然后,asnyc 一个函数里面,await上面的函数,url总是获取不到,是因为在初始化的时候,getSongUrl已经运行完了
export async function createSongs(musicData) {
return new Song({
id: musicData.id,
singer: filterSinger(musicData.ar),
name: musicData.name,
album: musicData.al.name,
duration: musicData.l.size,
image: musicData.al.picUrl,
url: await getSongUrl(musicData.id)
})
}
//这样就把createSongs方法定义成了一个promise方法,这样就能取到它的url值,直接调用createSongs,用.then处理promise回来的数据
_normalizeSongs(list) {
list.forEach(item => {
// ret.push(createSongs(item).then(data => data))
createSongs(item).then(data => this.songs.push(data))
})
}
自定义prefixStyle根据浏览器添加样式前缀
let elementStyle = document.createElement('div').style
let vendor = (() => {
let transformNames = {
webkit: 'webkitTransform',
Moz: 'MozTransform',
O: 'OTransform',
ms: 'msTransform',
standard: 'transform'
}
for (let key in transformNames) {
if (elementStyle[transformNames[key]] !== undefined) {
return key
}
}
return false
})()
export function prefixStyle(style) {
if (vendor === false) {
return false
}
if (vendor === 'standard') {
return style
}
return vendor + style.charAt(0).toUpperCase() + style.substr(1)
}
//使用自定义prefixStyle
import {prefixStyle} from 'common/js/dom'
const transform = prefixStyle('transform')
const backdrop = prefixStyle('backdrop-filter')
this.$refs.imgheight.style[transform] = `scale(${scale})`
使用create-keyframe-animation插件可以在js使用animation动画
//导入animation包
import animations from 'create-keyframe-animation'
const animation = {
0:{干嘛干嘛},
60:{干嘛干嘛},
100:{干嘛干嘛}
}
//注册animation动画的方法
animations.registerAnimation({
name: 'move',
//动画样式
animation,
//基础设置
presets: {
//持续时间
duration: 400,
easing: linear //线性动画
}
})
//将动画挂载到dom中
animations.runAnimation(this.$refs.cdWrapper,'move',done) //第一个参数是dom,第二个是动画名,第三个是结束的回调
//在结束的回调记得将动画销毁
animations.unregisterAnimation(‘move')
使用三目运算符和computed属性改变icon的图标和动态改变keyframe动画
字符串补零的方法
// 其中num为你传的字符串,n为你要补到的位数
_pad(num, n = 2) {
let len = num.toString().length
//其中用while是当n>2时的情况所需,‘0’为你要补的字符串,可在前或后补
while(len < n){
num = '0' +num
len++
}
return num //此方法可为前后补字符串用。
}
移动端事件方法
//对于移动端,浏览器提供了touchStart,touchMove,touchEnd三个方法
<scroll
@touchStart = 'touchStart'
@touchMove = 'touchMove'
@touchStart = 'touchEnd'
>
//在methods中定义
methods: {
//参数默认为调用事件的元素
touchStart(e){
let x = e.touchs[0].pageX //e.touches[0],代表点击的第一个位置,pageX是第一个位置的x坐标
}
......
}
</scroll>
getBoundingClientRect()
getBoundingClientRect用于获取某个元素相对于视窗的位置集合。集合中有top, right, bottom, left等属性。
<!
返回值类型:
rectObject.top:元素上边到视窗上边的距离;
rectObject.right:元素右边到视窗左边的距离;
rectObject.bottom:元素下边到视窗上边的距离;
rectObject.left:元素左边到视窗左边的距离;
!>
//一般是过去一个元素,然后去调用他对于视窗的距离,进行动态改变样式
rectObject = object.getBoundingClientRect();
rectObject.left //这就获取到元素左边到视窗左边的距离
vue中的mixins属性
<meta charset="utf-8">
minxin其实是一个对象,里面的结构大致跟普通组件的script里面的一样,有data属性,钩子函数和方法等
混入 (mixins) 是一种分发 Vue 组件中可复用功能的非常灵活的方式。混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被混入该组件本身的选项。
在实际项目中,可以新建一个js文件,导出一个minxin对象 在引用的组件中引入使用即可
这里例子就简单的跟官网一样帮助理解即可
选项合并
当组件和混入对象含有同名选项时,这些选项将以恰当的方式混合。
比如,数据对象在内部会进行浅合并 (一层属性深度),在和组件的数据发生冲突时以组件数据优先。
var mixin = {
data: function () {
return {
message: 'hello',
foo: 'abc'
}
}
}
new Vue({
mixins: [mixin],
data: function () {
return {
message: 'goodbye',
bar: 'def'
}
},
created: function () {
console.log(this.$data)
// => { message: "goodbye", foo: "abc", bar: "def" }
}
})
同名钩子函数将混合为一个数组,因此都将被调用。另外,混入对象的钩子将在组件自身钩子之前调用。
var mixin = {
created: function () {
console.log('混入对象的钩子被调用')
}
}
new Vue({
mixins: [mixin],
created: function () {
console.log('组件钩子被调用')
}
})
// => "混入对象的钩子被调用"
// => "组件钩子被调用"
值为对象的选项,例如 methods, components 和 directives,将被混合为同一个对象。两个对象键名冲突时,取组件对象的键值对
var mixin = {
methods: {
foo: function () {
console.log('foo')
},
conflicting: function () {
console.log('from mixin')
}
}
}
var vm = new Vue({
mixins: [mixin],
methods: {
bar: function () {
console.log('bar')
},
conflicting: function () {
console.log('from self')
}
}
})
vm.foo() // => "foo"
vm.bar() // => "bar"
vm.conflicting() // => "from self"