小程序和 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 协议》,转载必须注明作者和本文链接
讨论数量: 1

使用第三方框架进行转义区别更小不是更好吗? :blush:

4年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!