参考资料
练习题 icon lost
交流讨论
我的笔记
专栏课程

uni-app

(Union Application) 是一个基于Vue.js的前端框架;开发规范借鉴了微信小程序

前端技能点:

  • 前后端分离,后端给接口和API文档,注重前端
  • 用uni-app框架

作用:

  • 创业团队可以更快的开发上线一个app,更容易抢占互联网市场,获取利润
  • 原先多个人开发的工作现在只需要一个人完成,节省人力物力成本
  • 个人开发者私活利器,包办多端产品
  • 毕业设计多平台

优势:

  • 同一套代码编译多端(Android、IOS、H5、小程序)
  • 接近原生系统,效率更好
  • 利用Hbuiler X,开发效率高,内存占用少
  • 开发(人力、维护、时间)成本低
  • 学过Vue之后,学习成本很低
  • 支持npm与自定义组件
  • 社区活跃,版本迭代快

HBuilder X调试

点击工具-设置,添加小程序运行配置:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Qrwpm0H4-1620737310925)(D:\Desktop\markdown学习笔记\前端\uni-app.assets\image-20210329095358519.png)]

点击运行按钮-微信小程序开发者工具,会自动打开开发工具并运行:

Vue.js简介

Vue.js(读音 /vjuː/, 类似于 view) 是一套构建用户界面的渐进式框架。

Vue 只关注视图层, 采用自底向上增量开发的设计。

Vue 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。

MVC与MVVN思想

后端MVC开发模式

Model(数据增删改)+View(前端页面)+Controller(处理业务+路由)

前端MVVN开发模式

View(页面HTML)+Model(单页面的静态数据JSON)+ViewModel(核心调度者协调器)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5UPvXssA-1620737310932)(D:\Desktop\markdown学习笔记\前端\uni-app.assets\image-20210329111637677.png)]

ViewModel实现数据双向绑定:

  • 数据丢给VM来做数据渲染的动作,再交给HTML
  • 如果用户修改了HTML的数据,VM会再次传递到Model里面

测试MVVN双向绑定

uni-app框架中的页面全是.vue,编写第一个index.vue代码:

<!-- <template> <script> <style>这三个标签在每个页面都只能存在一个
	templete:View-->
<template>
	<!-- div -->
	<view class="content">
		<image class="logo" src="/static/logo.png"></image>
		<view class="text-area">
			<!-- 虚拟DOM:数据双向绑定 -->
			<text class="title">{{title}}</text> 
			<!-- :value 数据与data中的title进行绑定
				@input 事件绑定  "change" 事件名称-->
			<input type="text" :value="title" @input="change"/>
		</view>
	</view>
</template>

<script>
	// VM对象:协调者 调度器
	export default {
		// Model:所有的数据
		data() {
			return {
				title: 'Hello'
			}
		},
		onLoad() {

		},
		// methods:所有用户自定义的方法
		methods: {
			change(e){
				var txtTitle=e.detail.value;
				// 更新data中的title
				this.title=txtTitle;
			}
		}
	}
</script>

<style>
	.content {
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
	}

	.logo {
		height: 200rpx;
		width: 200rpx;
		margin-top: 200rpx;
		margin-left: auto;
		margin-right: auto;
		margin-bottom: 50rpx;
	}

	.text-area {
		display: flex;
		justify-content: center;
	}

	.title {
		font-size: 36rpx;
		color: #8f8f94;
	}
</style>

测试结果:input框中输入的内容,可以同步的回显在text页面框中

vue同样支持JSON对象和数组的渲染:

<view>
			I am {{student.age}} years old. <br/>
			I have skills such as: {{skill[0]}},{{skill[1]}},{{skill[2]}},{{skill[3]}}
</view>

		data() {
			return {
				title: 'Hello',
				student:{
					age:18
				},
				skill:["Java","HTML","CSS","Vue","uni-app"]
			}
		},

页面路由以及标题配置

页面路由

pages底下所有的页面都要在pages.json中配置页面路由,实际上创建页面时,框架也会为我们自动创建:

{
	"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
		{
			"path": "pages/index/index",
			"style": {
				"navigationBarTitleText": "uni-app"
			}
		}
	    ,{ //自动创建
            "path" : "pages/hello/hello",
            "style" :                                                                                    
            {
                "navigationBarTitleText": "私有页面标题",  //覆盖全局标题
                "enablePullDownRefresh": false
            }
            
        }
    ],
	"globalStyle": {   //标题栏
		"navigationBarTextStyle": "black",
		"navigationBarTitleText": "uni-app",
		"navigationBarBackgroundColor": "#F8F8F8",   //导航栏颜色
		"backgroundColor": "#F8F8F8"  //窗口背景色
	}
}

标题配置

	"globalStyle": {   //标题栏
		"navigationBarTextStyle": "black",
		"navigationBarTitleText": "uni-app",
		"navigationBarBackgroundColor": "#F8F8F8",   //导航栏颜色
		"backgroundColor": "#F8F8F8"  //窗口背景色
        //查看uni-app官网,有更多的参数属性可以配置
	}

宏观讲解项目配置

项目结构

static文件:css、js、jpg

unpackage文件:打包目录,会构建一个dev/app-plus(手机)、dev/mp-weixin(小程序);发布会有一个build/app-plus。

App.vue:提取每个页面公共css,可以在其他vue中使用(可以被局部style覆盖)

<style>
	/*每个页面公共css */
	.green{
		background-color: #4CD964;
	}
</style>

<view class="green" style="width: 300px; height: 300px;"> 调用 </view>

main.js:项目的入口文件,可以统一配置全局的对象、数组、函数(如url与用户信息)

manifest.json:项目配置与发布

  • 项目默认分配一个uni-app;
  • App图标、启动图配置是发布用的;
  • App模块权限是第三方的权限(支付、定位、摄象头等)
  • h5配置(https设置、端口设置)
  • 微信小程序配置(官方的App ID、本地测试环境建议取消勾选“检查安全域名和TLS版本”)

uni.scss:常用变量样式,预处理,用于插件开发

应用与页面的生命周期

应用的生命周期

app.vue中的函数触发时机:

<script>
	export default {
		onLaunch: function() { //当uni-app 初始化完成时触发(全局只触发一次)
			console.log('App Launch')
		},
		onShow: function() { //当 uni-app 启动,或从后台进入前台显示
			console.log('App Show')
		},
		onHide: function() { //当 uni-app 从前台进入后台
			console.log('App Hide')
		}
	}
</script>
微信小程序中额外的两个生命周期触发方法触发时机
onErroruni-app 报错时触发
onPageNotFound页面不存在监听函数

页面的生命周期

除了应用的触发方法,还有一些方法,可以查看官方文档:https://uniapp.dcloud.io/

onLoad() {
    console.log('页面加载')
},
onShow() {
    console.log('页面显示')
},
onReady() {
    console.log('页面初次渲染完成')
},
onHide() {
    console.log('页面隐藏')
},
onUnload() {
    console.log('页面关闭')
},
onShareAppMessage() {
    console.log('页面分享')
},
onPageScroll() {
    console.log('页面滚动')
},
onBackPress() {   // 不支持小程序,通常写在onLoad中
    console.log('页面返回')
},

由于测试需要跳转,跳转代码如下:

	<!-- open-type对应onBackPress()页面跳转 -->
	<navigator url="../index/index" open-type="navigateBack">
		<view class="green" style="width: 300px; height: 300px;"></view>
	</navigator>

px&upx像素

px是固定大小的像素,但每个手机的像素不一致,为了兼容不同的机型,引入了upx,根据屏幕大小做自适应。

750upx是屏幕的宽度,可以在不同机型上做自适应,1:1的显示一个正方形:

<view class="green" style="width: 750upx; height: 750upx;"></view>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JUFgJCdj-1620737310935)(D:\Desktop\markdown学习笔记\前端\uni-app.assets\image-20210330113009171.png)]

注意:字体和变宽都会设定为固定像素,用px即可(并不是所有地方都用upx)

数据绑定

在标签外部,都用{{表达式}}

{{student.age+'1'}}   //字符串拼接{{student.age>=18 ? '成年':'未成年'}}   //三元表达式

v-bind:

在标签内时,需要用v-bind:(也可以只写一个:)

<navigator v-bind:url=url >

事件处理

用户与应用交互的方式

创建event.vue做一些简单的测试:

<template>	<view>		<input type="text"  style="width: 300upx; height: 100upx; color: #55430e;"		 @input="change"		 @focus="focus"   		 @blur="blur"		 		 @confirm="confirm"		 @tap="tap"		 @longpress="longpress"		 @touchstart="touchstart"		 @touchend="touchend"		 @touchmove="touchmove"		 />	</view></template><script>	export default {		data() {			return {							}		},		methods: {  //所有函数写在methods对象中			focus(){				console.log("获得焦点")			},			blur(){				console.log("失去焦点")			},			confirm(){				console.log("点击完成/回车")			},			tap(){				console.log("触摸按压")			},			longpress(){				console.log("长按")			},			touchstart(){				console.log("触摸开始")			},			touchend(){				console.log("触摸结束")			},			touchmove(){				console.log("触摸移动")			},		}	}</script>

条件语法

条件渲染v-if与v-show

	<view>		<view v-if="isShow">			now you see me 		</view>		<view v-else>			can not see 		</view>		<!-- false:在前端隐藏整个标签的代码 -->		<view v-show="isShow">			now you see me 		</view>	</view>

三元运算

		<view v-if="sex==1?true:false">			男 		</view>				<view v-if="sex==1">			男 		</view>		<view v-else-if="sex==0">			女		</view>		<view v-else>			未知		</view>

列表渲染嵌套v-for

嵌套双循环需要指定index避免冲突

<template>	<view> 		<!-- (stu,stuIndex)   (对象,下标)  下标可以省略,但是在多重循环中,避免index冲突,显示定义成不一样的-->		<view v-for="(stu,stuIndex) in stuArray">			<view>学生姓名:{{stu.name}},年龄:{{stu.age}}</view>			<view>				擅长技能:				<!-- <view v-for="skill in stu.skills">{{skill}}</view> -->				<!-- block只显示对象的元素(简单的字符串拼接),而view显示标签(会换行) -->				<block v-for="(skill,skillIndex) in stu.skills">{{skill}},</block>			</view>		</view>	</view></template><script>	export default {		data() {			return {//循环遍历一个列表				stuArray:[					{						name:"joey",						age:21,						skills:["Java","HTML","CSS","Vue","uni-app"],					},					{						name:"carmine",						age:22,						skills:["Java","HTML","uni-app"],					},					{						name:"spark",						age:23,						skills:["HTML","CSS","Vue","uni-app"],					}				]			}		},		methods: {					}	}</script>

:key的作用

<!-- :key  保证组件和数据捆绑唯一 --><view v-for="stu in stuArray" :key="stu.id">    <!-- 用:value使复选款的value与{{}}表达式关联 -->    <checkbox :value="stu.name" >{{stu.name}}</checkbox></view><button type="primary" @click="addStu">新增学生</button>

条件编译(跨端)

**写法:**以 #ifdef 或 #ifndef 加 %PLATFORM% 开头,以 #endif 结尾。

  • #ifdef:if defined 仅在某平台存在
  • #ifndef:if not defined 除了某平台均存在
  • %PLATFORM%:平台名称

支持的文件

  • .vue
    <!-- #ifdef H5  -->    <view> 只在H5编译 </view>    <!-- #endif -->    <!-- #ifdef MP-WEIXIN  -->    <view> 只在微信小程序编译 </view>    <!-- #endif -->    <!-- #ifndef MP  -->    <view> 不在小程序全端编译,只在IOS、Android、H5编译 </view>    <!-- #endif -->
  • .js
	onLoad() {		// #ifdef H5		console.log("只在H5编译");		// #endif	},
  • .css
<style>	/* 在多端显示不同的颜色 */	.color {  		/* #ifdef H5 */		background-color: #4CD964;		/* #endif */				/* #ifdef APP-PLUS */		background-color: #007AFF;		/* #endif */				width: 200upx;		height: 200upx;	}</style>

Flex自适应布局(重点)

Flex 是 Flexible Box 的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性。

采用 Flex 布局的元素,称为 Flex 容器(flex container),简称"容器"。它的所有子元素自动成为容器成员,称为 Flex 项目(flex item),简称"项目"。

img

Flex容器的属性

flex-direction属性决定主轴的方向(即项目的排列方向)。

.box {  flex-direction: row | row-reverse | column | column-reverse;}

flex-wrap属性定义,如果一条轴线排不下,如何换行。

.box{  flex-wrap: nowrap | wrap | wrap-reverse;  不换行 | 换行 | 换行,第一行在上方;}

justify-content属性定义了项目在主轴上的对齐方式

.box {  justify-content: flex-start | flex-end | center | space-between | space-around;}flex-start(默认值):左对齐flex-end:右对齐center: 居中space-between:两端对齐,项目之间的间隔都相等(等比)space-around:每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。

align-items属性定义项目在交叉轴上对齐方式

.box {  align-items: flex-start | flex-end | center | baseline | stretch;}baseline: 项目的第一行文字的基线对齐。stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度。

align-content属性定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。(把轴线当作item来进行排列)

.box {  align-content: flex-start | flex-end | center | space-between | space-around | stretch;  }

导入外部样式

<style>	@import url("flex.css");</style>

Flex元素的属性

order属性定义项目的排列顺序。数值越小,排列越靠前,默认为0。

.item {  order: <integer>;}

flex-grow属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大。

.item {  flex-grow: <number>; /* 全为1 就等比放大*/}

flex-shrink属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。

.item {  flex-shrink: <number>; /* 设置为0 就不进行缩放 */}

flex-basis属性定义了在分配多余空间之前,项目占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小。

.item {  flex-basis: <length> | auto; /* 可以直接设置像素300upx */}

align-self属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch

.item {  align-self: auto | flex-start | flex-end | center | baseline | stretch;}

项目实战

tabBar

配置在page.json中:

"tabBar":{		"color":"#8F8F94",		"selectedColor":"#007AFF",		"backgroundColor":"#FFFFFF",		"borderStyle":"black",		"list":[			{				"pagePath":"pages/index/index",				"text":"首页",				"iconPath":"static/tabBar/index1.png",				"selectedIconPath":"static/tabBar/index2.png"			},			{				"pagePath":"pages/me/me",				"text":"我的",				"iconPath":"static/tabBar/mine1.png",				"selectedIconPath":"static/tabBar/mine2.png"			},			{				"pagePath":"pages/search/search",				"text":"搜索",				"iconPath":"static/tabBar/search1.png",				"selectedIconPath":"static/tabBar/search2.png"			}		]	}

swiper轮播图组件

Tips:输入"usw",可以自动生成swiper的模板

<view class="page">    <swiper :indicator-dots="true" :autoplay="true" class="carousel">        <swiper-item>            <image src="../../static/swiper/swiper_1.jpg" class="carousel"></image>        </swiper-item>        <swiper-item>            <image src="../../static/swiper/swiper_2.jpg" class="carousel"></image>        </swiper-item>    </swiper></view>
.carousel {	width: 100%;	height: 440upx;   //根据图片的高度而设定}

拉取数据swiperList(json),并进行列表渲染:

<swiper-item v-for="swiper in swiperList">    <image :src="swiper.image" class="carousel"></image></swiper-item>

原生导航栏禁用

ps:小程序中的状态栏禁不掉

在pages.json中的style属性添加禁用:

"style": {    "app-plus": {        "titleNView":false  //禁用    }}

引入组件实现全局变量

方法一

在commons/commons.js中提取全局变量:

//提取公共文件const doubanUrl ="https://images.weserv.nl";  //豆瓣电影export default{	doubanUrl  //常量导出}

导入common:

import common from "../../commons/commons.js"//拼接使用"image":common.doubanUrl+"/?url=img1.doubanio.com/view/photo/l/public/p2410755737.webp",

方法二

也可以在main.js中挂载到Vue:

Vue.prototype.doubanUrl="https://images.weserv.nl";

所有页面都可以获取Vue对象(this.即可,无需import):

"image":this.doubanUrl+"/?url=//img3.doubanio.com/view/photo/l/public/p2556561071.webp",

小程序Https

需要登录之后对域名进行配置,并且只支持Https协议。

一旦允许某些域名之后,就可以不用勾选“不校验合法域名、HTTPs证书”。

scroll-view可滚动视图

通过本地json获取热门影像的数据:

// 获取热门数据getHotData(){    // 特别注意:非H5端不能用uni.request来请求本地json数据!!!    // const dataRes=await this.$http({url:'/new_movies.json'})    const {subjects:dataRes}=require('../../static/mock/top250.json')    // 截取10条数据    let newArr=[]    for(let i=0;i<dataRes.length;i++){        if(i+this.hotCount-10<this.hotCount){            let item=dataRes[i+this.hotCount-10]            // 对图片做处理            item.images.small=item.images.small.replace('https://','https://images.weserv.nl/?url=')            newArr.push(item)        }    }    this.hotData=[...this.hotData,...newArr]},

利用v-for来列表渲染动态的滚动视图(评分稍后补充):

<scroll-view scroll-x="true" class="page-block hot">    <view class="single-poster" v-for="item in hotData" :key="item.id">        <view class="poster-wapper">            <image :src="item.images.small"  class="poster"></image>            <view class="movie-name">                {{item.title}}            </view>            <view class="movie-score-wapper">                ...                <view class="movie-score">                    9.0                </view>            </view>        </view>    </view></scroll-view>

自定义组件

编写components/helloComp.vue文件:

<!-- 定义组件名称为 helloComp --><template name="helloComp">	<view>		{{msg}}		<!-- 动态接收 -->		<input type="text" :value="myval" class="txt"/>	</view></template><script>	export default {		//定义组件名称为 helloComp		name:"helloComp",		data() {			return {				msg:"这是自定义组件~~~"			};		},		//定义组件内部使用的属性		props:{			//自定义变量,用于接收父组件(首页或者其他页面)传入的参数值			myval:{ //传入的是一个对象				type: String //定义参数类型			}		}	}</script><style>	.txt{		color: red;	}</style>

在需要使用的vue中导入:

	// 导入自定义组件	import helloComp from "../../components/helloComp.vue"

在components对象中注册组件:

		components:{   //在components对象中注册			helloComp,			trailerStars		}

在template中使用组件:

    <!-- 使用自定义组件 -->    <helloComp myval="Hello next~~~"></helloComp>

通过自定义组件动态显示得分

评分+星星的组件:

<template name="trailerStars">	<view>		<view class="movie-score-wapper">			<image v-for="yellow in yellowScore"			src="../static/icons/star-yellow.png" class="star-icon"></image>			<image v-for="gray in grayScore"			src="../static/icons/star-gray.png" class="star-icon"></image>						<view class="movie-score" v-if="showNum==1">				{{innerScore}}			</view>		</view>	</view></template><script>	export default {		name:"trailerStars",		data() {			return {				yellowScore:0,				grayScore:5    //默认显示5个灰色星星			};		},		props:{			innerScore:0,  //定义外部传入的分数			showNum:0      //定义是否需要显示具体的得分数  1:显示 0:不显示		},		//生命周期,组件创建完成后被调用		created() {			var tempScore=0			if(this.innerScore != null && this.innerScore != undefined && this.innerScore != ''){				tempScore=this.innerScore;			}			this.yellowScore=parseInt(tempScore/2);  //计算黄色星星			this.grayScore=5-this.yellowScore;		}	}</script><style>	.movie-score-wapper{		display: flex;		flex-direction: row;	}	.star-icon{		width: 20upx;		height: 20upx;		margin-top: 6upx;	}	.movie-score{		font-size: 12px;		color: grey;		margin-left: 8upx;	}</style>

调用组件:

<trailerStars :innerScore="item.rating.average" showNum="1"></trailerStars>

vedio组件开发

vedio组件来开发热门视频模块(hotTrailerList从猫眼电影拿):

<view class="hot-movies page-block">    <video v-for="hotTrailer in hotTrailerList" :src="hotTrailer.src"     :poster="hotTrailer.poster" class="hot-movie-single" controls>    </video></view>

配置相应的CSS样式:

/* 热门预告 */.hot-movies{	display: flex;	flex-direction: row;	flex-wrap: wrap;	justify-content: space-between;   //视频间隙	padding: 0 20upx 20upx 20upx;}.hot-movie-single{	width: 350upx;	height: 220upx;	margin-top: 10upx;}
资料来源 微信小程序开发入门——uni-app框架
博客作者 Carmine逸
前往答题
发布见解