赞
踩
小程序开发框架:mpvue(一)初篇
小程序开发框架:mpvue(二)项目代码分析
小程序开发框架:mpvue(三)完成一个积极干净的mpvue初创项目
任何语言/框架的学习都离不开项目实战,这篇开始我们将通过实际操作一个项目来学习微信小程序和vue技术的方方面面;
1: 首先我们在小程序首页引入一个组件,并介绍下父组件与子组件是如何进行相互交互的
实现效果如上,在上面的效果中,绿色边框是以组件的形式引入到主页当中
该章节主要涉及的知识点有
1. 微信组件image的使用
2. 如何自定义/引入组件
3. 让一个div铺满剩余的页面
4. 组件交互的三种技法
<image class="welcome" mode='aspectFit' :src="welIcon"></image>
微信小程序提供了一个image组件用于替代html中的img标签,这个标签可以更快的实现图片的裁剪和缩放;
上面代码使用了微信的image组件,并设置其mode为aspectFit,表示保持纵横比缩放图片,使图片的长边能完全显示出来。也就是说,可以完整地将图片显示出来,当然mode还有很多设置方式,这里就不一一介绍,你只要记住微信的image组件可以通过mode来设置图片的裁剪和缩放即可,具体的请查阅微信image组件使用API
<template> </template> <script> export default { // 这里只是对组件命名,其实这里也可以不写 name: 'LoginModule', data () { return { } }, methods: { } } </script> <style> </style>
一个组件默认包含template,script和style三个部分,有了这个基础我们就能写自己的vue组件了
第9行,我们将这个组件命令为LoginModule,其实这行代码也可以不写
然后我们在父组件pages/indexs/index.vue中引入LoginModule组件,主要有三个步骤
1)通过import引入组件
import LoginView from '@/components/login'
2)在components中申明这个组件
components: {
LoginView
},
3)在template中使用这个组件
<template>
<!-- 因为登录有可能在其他地方进行,顾登录的页面封装成单独的组件 -->
<div class="container">
<div class="title">
<p class="loginPeople" v-if="isShowLoginPeople">{{loginWho}}</p>
<image class="welcome" mode='aspectFit' :src="welIcon"></image>
</div>
<div class="login">
<!-- 引入子组件 定义一个on的方法监听子组件的状态-->
<login-view v-bind:inputName="name" v-on:clickLogin="showLoginPeople"></login-view>
</div>
</div>
</template>
这里我们有几个注意的地方
1)import后跟引入组件的名字,components中的名字要和其保持一致
2)在templeta中可以通过LoginView来使用该组件了,因为采用了驼峰命名法,顾在使用的时候可以使用xx-xx的形式,如第10行
<template>
<!-- 因为登录有可能在其他地方进行,顾登录的页面封装成单独的组件 -->
<div class="container">
<div class="title">
<p class="loginPeople" v-if="isShowLoginPeople">{{loginWho}}</p>
<image class="welcome" mode='aspectFit' :src="welIcon"></image>
</div>
<div class="login">
<!-- 引入子组件 定义一个on的方法监听子组件的状态-->
<login-view v-bind:inputName="name" v-on:clickLogin="showLoginPeople"></login-view>
</div>
</div>
</template>
这个页面有两个div,一个title,一个login,我们想让login铺满剩下的布局,则可以采用如下的方式
.login{
width: 100%;
position: absolute;
top: 150px;
bottom: 0px;
left: 0px;
background: #ea5c54;
}
这里的设计思想是通过绝对对位让元素脱离文档流,然后使其定位到底部,即bottom和left均为0,
那么只要top的距离为title这个div的高度即可
1)子组件与父组件通信
子组件通过this.$emit的方式触发父组件监听的事件,当父组件收到事件调用时,触发父组件的方法
methods: {
login () {
let userName = this.inputName
this.$emit('clickLogin', userName)
}
}
如上,子组件定义了一个login方法,当调用login方法的时候,发布一个clickLogin方法出去,有点类似广播;
<div class="login">
<!-- 引入子组件 定义一个on的方法监听子组件的状态-->
<login-view v-bind:inputName="name" v-on:clickLogin="showLoginPeople"></login-view>
</div>
如上,在父组件引用子组件的时候,注册一个监听,即此处的第3行,当收到子组件发出的clickLogin广播的时候,便会触发自身的showLoginPeople方法,showLoginPeople方法定义如下
methods: {
showLoginPeople (user) {
}
}
此处的参数user即子组件传过来的值
2)父组件与子组件通信
子组件定义props属性用于接收父组件传过来的值
props: {
inputName: String,
required: true
},
父组件通过v-bind的方式传递对应的值即可
<login-view v-bind:inputName="name"></login-view>
如果在父组件中想调用子组件的某一个方法,我们可以使用$refs先去获取该DOM元素,然后就可以通过该实例调用组件的方法了,
// 在父组件中引入了一个FilterDialog的组件
<filter-dialog ref="wholeFilterDialog"></filter-dialog>
// 在父组件中就可以通过$refs.wholeFilterDialog获取该组件实例,然后调用该组件的show方法
this.$refs.wholeFilterDialog.show()
3)非父子组件通信: 我们通过vuex
vuex我们首先要了解如下几个概念,为了解释起来不那么官方,我会用通俗的语言来描述
3.1)state
即你定义的状态管理里面可以维护的数据
3.2)getters
即你可以通过getters的方式去获取你定义的数据,或者对维护的数据进行操作,然后返回出来
3.3)mutations
采用同步的方式修改维护的数据
3.4)action
采用异步的方式去操作mutation,你可以将action视为对mutations的一个封装,他和mutations最大的区别是,action支持异步操作
3.5)mapstate
从名字就可以看出,他是对state的映射,方便我们获取state,而不用使用$store.state…这种冗长的方式
3.6)mapMutations
他是对mutations的映射,也是用于简化操作的
下面我们将实现的效果是这样的,大家最好自己实现下,要不还是纸上谈兵
1)小程序启动的时候,给子组件LoginModule传递一个值‘扬帆起航’,并显示在用户名编辑框中
2)当用户点击登录按钮,父页面显示正在登录的用户名
3)当用户点击登录按钮的时候,通过vuex对用户名进行存储
效果如下
关键代码如下
1)主页面代码
<template> <!-- 因为登录有可能在其他地方进行,顾登录的页面封装成单独的组件 --> <div class="container"> <div class="title"> <p class="loginPeople" v-if="isShowLoginPeople">{{loginWho}}</p> <image class="welcome" mode='aspectFit' :src="welIcon"></image> </div> <div class="login"> <!-- 引入子组件 定义一个on的方法监听子组件的状态--> <login-view v-bind:inputName="name" v-on:clickLogin="showLoginPeople"></login-view> </div> </div> </template> <script> // 通过import的方法导入该组件,这样就可以使用通过LoginView来使用该组件了,因为采用了驼峰命名法,顾在使用的时候可以使用xx-xx的形式 // 在早期的mpvue版本中,不是通过@符号引入组件,而是通过~符号引入组件 import LoginView from '@/components/login' export default { components: { LoginView }, data () { return { // 欢迎icon welIcon: '/static/welcome.png', // 默认登录的名字 name: '扬帆起航', // 是否显示正在登录的用户名 isShowLoginPeople: false, loginWho: '' } }, methods: { showLoginPeople (user) { this.isShowLoginPeople = true this.loginWho = '正在登录的是' + user let whoLogin = this.$store.state.userName console.log('**whoLogin**' + whoLogin) } } } </script> <style scoped> body { /* 清空页面的margin和padding */ margin: 0px; padding: 0px; } /* 为了实现页面的兼容,即login这个div需要占满剩下的页面,这里的设计思想是 通过决定对位让元素脱离文档流,然后使其定位到底部,即bottom和left均为0, 那么只要top的距离为title这个div的高度即可 */ .title{ width: 100%; height: 150px; position: relative; background: #ea5c54; } .welcome{ width: 126px; height: 100px; position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); } .login{ width: 100%; position: absolute; top: 150px; bottom: 0px; left: 0px; background: #ea5c54; } </style>
2)子组件代码
<template> <div class="loginParent"> <div class="userContain"> <img class="userIcon" src="/static/name.png"> <input class="userInput" placeholder="用户名" maxlength="16" type="text" v-bind:value="inputName" v-model="inputName" ref="username"> </div> <div class="login_fields__password"> <img class="icon-password" alt src="/static/pasword.png"> <input class="input-password" v-bind:type="inputType" placeholder="密码" maxlength="16"> </div> <div class="login_fields__submit"> <input type="button" value="登录" @click="login"> </div> </div> </template> <script> import { mapMutations } from 'vuex' export default { // 这里只是对组件命名,其实这里也可以不写 name: 'LoginModule', props: { inputName: String, required: true }, data () { return { inputType: 'password' } }, methods: { // mapMutations为语法糖,一个辅助函数,mapActions/mapMutations只是把action/mutation函数绑定到你的methods里;你调methods里的方法的时候照常传参就可以了。 ...mapMutations(['setUserName']), // 相当于this.$store.commit('setUserName','具体传递的值'),提交这个方法 login () { let userName = this.inputName this.setUserName(userName) this.$emit('clickLogin', userName) } } } </script> <style> .userContain{ margin-top: 30px; margin-left: 70px; } .userIcon { display: inline-block; width: 26px; height: 26px; } .userInput { display: inline-block; width: 140px; border-style: solid; border-width: 1px; font-size: 12px; margin-left: 20px; } .login_fields__password{ margin-top: 30px; margin-left: 70px; } .icon-password { display: inline-block; width: 26px; height: 26px; } .input-password { display: inline-block; width: 140px; border-style: solid; border-width: 1px; font-size: 12px; margin-left: 20px; } .login_fields__submit { margin-top: 90px; } </style>
3)vuex部分
import Vue from 'vue' import Vuex from 'vuex' import * as getters from './getters' import * as actions from './actions' import * as mutations from './mutations' Vue.use(Vuex) // state类似于该类的属性/状态 // getters, 通过getters可以实现对该类属性/状态的获取和修改 // mutations, 类似于一个提交操作,mutations中一般是同步方法,用于修改该类的属性/状态 // actions, 也是一个提交操作,他和mutation的最大区别就是actions可以包含一个异步操作 // mapGetters 这是一个辅助函数,仅仅是将store中的getters映射到局部计算属性中,用法和mapState类似 const state = { // 定义一个该类的属性/状态userName,其默认值为侠骨柔情 userName: '侠骨柔情' } // 引入的各大模块 const store = new Vuex.Store({ state, getters, actions, mutations }) export default store
具体的工程可在如下链接下载
mpvue项目实战一
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。