小程序和 Vue 的区别 [入门]
前言
博客小程序第一版本发布了 搜索小程序 ==遥近博客== , 就可以在手机上看文章了
生命周期
关于Vue的生命周期,你可以看 Vue生命周期, 相比Vue,小程序的生命周期有点特别,它有全局生命周期、页面生命周期以及组件生命周期
全局生命周期
全局生命周期需要你在app.js文件中定义,有以下几个生命周期
onLaunch – 小程序初始化完成,全局只触发一次
onShow – 小程序启动时,或者从后台进入前台
onHide – 小程序从前台进入后台时执行
onError – 小程序运行脚本出错或者api调用失败时执行,会带上错误信息
==执行顺序: onLaunch–> onShow –> onHide==
其中, ==onShow以及 onHiden会多次触发==,比如你从小程序切换到微信聊天再切换回来,可以监察用户的行为
页面生命周期
页面的生命周期主要有以下几种:
onLoad
一个页面只会执行一次, 并且==可以获取当前页面的路径中的 query 参数==
onShow
页面显示/切入前台时触发,会执行多次
onReady
表示页面初始渲染完毕, 只会执行一次, ==对界面内容进行设置的API需要该钩子结束后执行==
onHide
页面隐藏/切入后台时触发,==例如 wx.navigateTo或者tab切换到别的页面执行==
onUnload
页面卸载时触发, ==例如 wx.redirectTo或wx.navigateBack到其他页面时==
==注意点==:当切换页面需要多次渲染数据改变状态,建议在onShow中使用,当只需初始化一次的时候,可在onLoad或者onReady中使用。当需要清除定时器时,可在onUnload中使用
==切换页面时触发的生命周期==:
当首次加载A页面,A触发的生命周期为:onLoad –> onShow –> onReady,从A页面切换到B页面时,A页面触发onHide,B页面触发的生命周期顺序与上面一致,当B页面返回到A页面时,触发onUnload,当不清缓存,再次进入A页面时,只触发onShow
想了解更多,你可以查看 PageApi
组件生命周期
常用的有以下几种:
created
组件刚刚被创建,==此时还不能调用this.setData方法==
attached
在组件实例进入页面节点树时执行, ==此时可以使用this.setData方法,读取节点数据, 例如wx.createSelectorQuery==
detached
在组件实例被从页面节点树移除时执行
想了解更多: 查看 组件生命周期
页面/路由 跳转
在Vue中,我们通过router对象的 push 或者 replce 方法进行路由的跳转, 已达到显示对应的页面,
小程序有所区别, 因为它有tab页,跳转会有所区别
wx.switchTab
可以跳转到对应的tab页面,==需要在app.json文件中定义tabBar字段设置对应的路径以及名称==
wx.reLaunch
关闭所有页面,打开到应用内的某个页面
路径为代码包中对应页面的路径,可以传递参数
wx.redirectTo
关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面
wx.navigateTo
保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面。使用 wx.navigateBack 可以返回到原页面。
==页面跳转的时候,想传递数据==
定义succsee方法, 将需要传递的数据进行传送, 如index页面跳转到page1页面
// index.js
wx.navigateTo({
url: '/page1/page1?id=666',
success: function (res) {
// 通过eventChannel向被打开页面传送数据
res.eventChannel.emit('acceptDataFromOpenerPage', { data: 'test' })
}
})
在 page1 中 ==onLoad== 钩子进行接收
onLoad: function (option) {
console.log(option) // {id: 666}
const eventChannel = this.getOpenerEventChannel()
eventChannel.on('acceptDataFromOpenerPage', function (data) {
console.log(data) // {data: test}
})
}
如果页面跳转成功后, 跳转到的页面某些数据想传递给原来的页面
在index.js文件中,在==定义一个events对象==, 接收数据(监听事件)
events: {
// 为指定事件添加一个监听器,获取被打开页面传送到当前页面的数据
acceptDataFromOpenedPage: function(data) {
console.log(data)
},
someEvent: function(data) {
console.log(data)
}
...
}
在page1.js文件中, 传递数据(发出事件)
eventChannel.emit('acceptDataFromOpenedPage', {data: 'test'});
eventChannel.emit('someEvent', {data: 'test'})
想了解更多, 你可以查看微信路由API
语法相关
数据绑定
在Vue中,我们通过bind来进行硬绑定
<img :src="imgSrc"/>
而在小程序,你需要通过大括号的方式表示
<image src="{{imgSrc}}"></image>
列表展示
在Vue中,我们通过v-for, 小程序我们使用wx:for
显示与隐藏元素
vue中,使用v-if 和v-show控制元素的显示和隐藏
小程序中,使用wx-if和hidden控制元素的显示和隐藏
事件绑定
vue中,我们通过@click 来绑定点击事件,stop时间修饰符来阻止冒泡, 在小程序,你需要使用bindtap来绑定点击事件(传递事件的字符串名称), ==catchtap来定义阻止冒泡的点击事件==
或者你可以定义一个wxs文件, 里面写相应的逻辑
<wxs module="wxs" src="./test.wxs"></wxs>
<view id="tapTest" data-hi="WeChat" bindtap="{{wxs.tapName}}"> Click me! </view>
function tapName(event, ownerInstance) {
console.log('tap wechat', JSON.stringify(event))
}
module.exports = {
tapName: tapName
}
触发事件的时候,vue想传递数据,只需要在函数中进行传参即可
小程序事件传递参数, 需要在组件的wxml中定义dataset,通过currentTarget对象获取
<view data-alpha-beta="1" data-alphaBeta="2" bindtap="bindViewTap"> DataSet Test </view>
Page({
bindViewTap:function(event){
event.currentTarget.dataset.alphaBeta === 1 // 会转为驼峰写法
event.currentTarget.dataset.alphabeta === 2 // 大写会转为小写
}
})
数据双向绑定
vue中,通过使用v-model可以很方便的实现, 小程序需要使用bindinput来绑定一个事件,再setData来改变值
取值
vue中通过this.xxx 读取, 小程序需要使用this.data.xxx读取
通信
开发中, 组件之间通信几乎是必不可少的,下面是vue和小程序通信之间的一些总结
父组件传递子组件
==Vue传递==
Vue中父组件传递数据给子组件,我们通过prop将需要传递的数据给到子组件中
<parent>
<child :list="list"></child> //在这里绑定list对象
</parent>
子组件定义props对象接受相应的数据
props:{
list:{
type:Array,//type为Array,default为函数
default(){
return [
"hahaxixihehe"//默认初始值
]}}
},//用props属性进行传数据,此时子组件已经获取到list的数据了
data(){
return {}
}
==父组件传递给子组件的数据,不能改变==
==小程序传递==
小程序传递跟Vue类似, 一样通过props传递,只是语法有所区别
<articleItem wx:for="{{articles}}" wx:key="{{index}}" articleItem="{{item}}"/>
子组件定义properties对象接受对应的数据
properties: {
articleItem: {
type: Object,
value: {}
}
}
子组件与父组件通信
在Vue中, 子组件跟父组件通信,通过$emit来实现
在子组件中我们通过 $emit 向父组件发送一个事件,并且传递数据
this.$emit('success',false);
父组件通过绑定自定义事件接受
<app-form v-bind:dialogCreate = "dialogCreate" v-on:success="success(res)"></app-form>
methods: {
success(res){
this.dialogCreate = res;
}
}
小程序中,跟Vue差不多, 只是语法不一样, 小程序不是 $emit ,而是 使用 ==triggerEvent== 发送事件给父组件, 然后在wxml中bind: 方法名称 来绑定自定义事件触发
兄弟之间通信
vue中兄弟之间通信,可以将需要传递到的数据放到父组件,父组件提供一个方法给到子组件,子组件触发方法改变数据, 父组件再将新的数据给到兄弟组件, 让父做一个中间人,当然,我们也可以使用事件总线(eventBus)来进行
主要是在Vue的原型上添加一个Vue的实例,或者创建一个Vue的实例,需要使用到的地方引入, 我们就使用这个vue的实例通过on 和emit 来实现通信, 它的原理就是通过公用一个vue的实例来进行事件的发放和监听,已达到数据共享的目的,==关于小程序兄弟组件通信,目前比较常用的方法是,通过父组件作为中间人==
父组件获取子组件
在vue中,父组件调用子组件的方法比较简单,可以给组件定义ref或者通过$children来读取到子组件,直接调用组件对应的方法即可,==ref需要确保你的子组件已经在页面渲染, 不然没法获取==
// 父组件
<template>
<component-a ref="comA"></component-a>
</template>
<script>
export default {
mounted () {
const comA = this.$refs.comA;
console.log(comA.title); // Vue.js
comA.sayHello(); // 弹窗
}
}
</script>
在小程序中,也有类似的方法, 我们可以通过给子组件绑定一个id值, 然后在 通过 ==selectComponent== 函数获取对应id的组件实例,就可以轻松的调用子组件的方法和访问对应的数据了
父组件中我们如下定义
// index.wxml
<test id='test'></test>
<button bindtap="test">触发子组件方法</button>
// index.js
test () {
let child = this.selectComponent('#test')
console.log(child) // 子组件实例
child.fun() // 调用子组件的方法
console.log(child.data.test) // 读取子组件的数据或者改变都可以
}
子组件js文件
data: {
test: '我的子组件数据'
},
methods: {
fun () {
console.log('我的子组件方法')
}
}
子组件获取父组件
既然我们可以通过$children获取子组件的,相应的我们子组件可以获取父组,vue中我们可以通过this.$parent来获取父组件,这样就可以轻松访问父的方法或者数据
小程序中,我们可以在子组件使用 ==selectOwnerComponent== 来获取父组件的实例
全局通信方式
vue中如果该数据使用地方较多,推荐使用vuex来管理, 在小程序中,建议使用 globalData 来存放多个地方使用到的数据
vue通信拓展
vue还有2种用的比较少用的通信的方式,这些通信方式适合在一些高级组件
$attrs和$listeners
==它们可以实现父组件的数据传递到深层次的子组件中,改变父组件的数据==
我们平时通过prop将数据传递给子组件, 子组件需要props对象来进行接收, 但是如果我们没有在props中接收对应的数据,那么这个数据就没法使用的,那么这些数据去哪里了呢, 它会作为父组件根元素的attribute显示在dom元素中
而在子组件中, ==$attrs 可以访问到没有给使用到的props属性==
// 父组件传递数据
<Button type='success' @click="test" size="medium" to="/btnTest">跳</Button>
// 子组件中的prop中我们并不接收to的值
<span>{{this.$attrs}}</span>
这个时候this.$attrs打印的值就是 to 传递过来的数据,我们就可以通过v-bind的方式传递给更深层次的组件, 为了不让父组件的attribute中显示to的值, 我们需要在子组件中设置==inheritAttrs: false==, 这样你的父组件就不会显示你子组件中没在props中接受的数据,保证你的数据安全
// 子组件中的prop中我们并不接收to的值
<span>{{this.$attrs}}</span>
<test v-bind="$attrs"></test> // 传递给更深的子组件
那最终的子组件拿到了数据之后,我应该如何改变我父级的数据呢, 这个时候我们就可以在子组件中v-on绑定 $listeners 让更深层次的子组件可以获取到父组件中的自定义事件,我们就可以在更深层次的子组件中 $emit 发送事件,来触发父组件的方法从而达到数据的更新
<span>{{this.$attrs}}</span>
<test v-bind="$attrs" @test2="handleClick" v-on="$listeners"></test> // 传递给更深的子组件
// 更深层次的子组件中
methods: {
changeParentData () {
this.$emit("change", 'ninhao') // 爷爷的方法
this.$emit("test2", 'ninhao') // 父级的方法
}
}
provide/inject
刚刚的方法的确帮我们解决了很多的通信的问题,但是视乎有点麻烦, provide/inject可以更好的帮助我们深层次的通信
我们可以在父组件中定义provide对象/对象函数,它可以让所有的子孙元素都可以使用到你在其定义的值
// 父组件中
provide() {
return {
color: this.color
},
data () {
return {
size: 'medium',
color: 'green'
}
}
},
子组件中通过inject通过key获取对应的值
inject: ['color']
==需要注意的是, 子组件中获取到的父组件的值,是不响应的,也就是父改变了,子不会改变==
==如果想父改变子同时改变,可以传递的是父级的实例==,那么父改变的时候,子的数据也会相应的改变,但是这样会造成不必要的methods等父级数据传递
第二种方法就是==通过 observable 方法 来让你的对象是可监听的==
这个时候,我们在provide中定义data的值, 这样确保你传递的对象是可响应的, 那么父级改变的时候,你的子级也会相应的改变了
// 父组件中
provide() {
this.data = Vue.observable({color: 'green'})
return {
data: this.data
}
},
methods: {
changeColor () {
this.data.color = 'red'
console.log(this.color,23232)
}
}
本作品采用《CC 协议》,转载必须注明作者和本文链接
使用第三方框架进行转义区别更小不是更好吗? :blush: