mpvue 踩坑笔记
一直想写个小程序,前段时间发现 mpvue 这个框架,可以用 vue 写小程序。简直开心,因为 leader 是个忠实的 react 迷弟,所以 mpvue 的出现同时满足我练手 vue 和小程序的需求,笑容逐渐失控.jpg。
项目的搭建神马的就不说了,可以看 这篇介绍 或者 mpvue 官网。
emmmm.....那个,下面就是我自己练手时遇到的坑:
1. 小程序的事件 bind 需要替换为 @
比如用户登录:
<button open-type="getUserInfo" lang="zh_CN" bindgetuserinfo="onGotUserInfo">获取用户信息</button>
在 mpvue 中就需要替换为:
<button open-type="getUserInfo" lang="zh_CN" @getuserinfo="onGotUserInfo">获取用户信息</button>
2. mpvue 不支持自定义指令 directives
场景是这样,页面中间有个输入框,点击之后跑到顶部,然后让输入框获取焦点。vue 中很常见的解决方式是定义一个自定义指令,但是发现 mpvue 不支持。所以我的解决方法是在 data 中添加一个变量,通过改变这个变量的值来控制输入框的焦点。
<template>
<input
:focus="focus"
:disabled="!canInput"
v-model="text"
@click="onInputClick"
@focus="onTextFocus"
@blur="onTextBlur" />
</template>
<script>
export default {
data () {
return {
text: '',
canInput: false,
focus: false,
}
},
methods: {
onTextFocus () {
this.focus = true
},
onTextBlur () {
this.focus = false
},
onInputClick () {
if (!this.canInput) {
this.canInput = true
setTimeout(() => {
this.focus = true
}, 200)
}
},
}
}
</script>
可能有同学问,为什么要手动控制获焦呢,点击的时候让输入框自己获取焦点不就行了嘛。
因为在这个场景下,点击之后会有个 0.2s 的动画从页面中间跑到顶部,如果让输入框自己获取焦点,那么点击的一瞬间输入框会出现光标,然后 0.2s 后输入框移动到顶部,这个过程就会有种卡顿的感觉。
3. 对 dom 使用 ref,返回 undefined
这个场景是有个列表,以卡片的形式水平依次排开,用户可以左右滑动查看。首先想到的就是 swiper4中文网,但是初始化的时候就GG了,因为无法使用 ref 获取 dom。去 issue 页了解到 v1.0.9 后支持子组件的引用,但对 dom 的支持意愿不大。然后就用了微信小程序提供的 swiper 组件代替。
<template>
<div ref="swiper" class="swiper-container" id="swiper1">....<div>
</template>
<script>
export default {
mounted () {
console.log(this.$refs.swiper)
// undefined
}
}
</script>
4. v-for 用在组件上刷新的问题
场景是这样,调接口拿到数据列表数组赋值给 data 中的一个变量 list,循环渲染 <ListItem />
组件。然后接口数据改变,即 list 也跟着改变,但是子组件内部却没有改变。
<template>
<div class="list">
<ListItem :key="item.id" v-for="item in list" :item="item"/>
</div>
</template>
<script>
export default {
data () {
list: []
},
methods: {
async getList () {
const list = await get(...)
this.list = list
}
}
}
</script>
// ListItem 组件
<template>
<div>
{{item.value}}
</div>
</template>
<script>
export default {
props: ['item'],
updated () {
console.log(this.item)
}
}
</script>
在 ListItem 组件的 updated
生命周期里打印父组件传来的数据,发现没有更新,还是上一次的数据。这个问题出现的原因研究了很久也没有找到(菜- -),然后试着把循环放到 ListItem 里,这个问题就解决了。
<template>
<div class="list" v-if="list.length > 0">
<ListItem :list="list" :query="text" />
</div>
</template>
// ListItem
<template>
<div class="list-container">
<div
class="list-item"
v-for="item in list"
:key="item.id">
{{item.value}}
</div>
</div>
</template>
如果有遇到过这种问题的同学或者解了的大神,求讨论。。。
5. 无法通过 methods 返回值在 html中赋值
如下赋值在 mpvue 中是行不通的。
<template>
<div id="example">
<p>Original message: "{{ message }}"</p>
<p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
</template>
<script>
export default {
data () {
return {
message: 'hello mpvue'
}
},
methods: {
reversedMessage () {
return this.message.split('').reverse().join('')
}
}
}
</script>
所以这种情况还是要用 computed 来赋值。
但是在循环中,需要根据情况来修改赋值,用 computed 就不好实现,然后 methods 赋值又不支持,所以想了个曲线的实现方式:methods + watch。
<template>
<div>
<h2>
<span
:class="{highlight: item.color}"
:key="i"
v-for="(item, i) in scKey">{{item.text}}</span>
</h2>
<p>
<span
:class="{highlight: item.color}"
:key="i"
v-for="(item, i) in content">{{item.text}}</span>
</p>
</div>
</template>
<script>
export default {
props: ['item', "query"],
data () {
return {
scKey: [],
content: []
}
},
mounted () {
this.getScKey()
this.getContent()
},
watch: {
item () {
console.log('watch')
this.getScKey()
this.getContent()
}
},
methods: {
getScKey () {
// 一顿操作
this.scKey = [ ... ]
},
getContent () {
// 二顿操作
this.content = [ ...]
}
}
}
</script>
以上就是我最近尝试 mpvue 遇到的比较大的坑,如有不对的地方、或者同学们有更好的解法,欢迎谈论交流,笔芯🤓😁。