uni-app小程序开发 基础知识2

目标:

构建一个文章发表平台。

我们先来写一个静态框架。

以下是

首页初代码+文章列表页代码:

html 复制代码
<template>
	<view class="content">
		<!-- 轮播图 -->
		<swiper  class="swiper-container" autoplay="true" interval="3000" circular="true">
			<!-- 每个item里循环 -->
			<swiper-item >
				<!-- 这是自己的轮播内容 img -->
				<image src="" class="swiper-image"></image>
			</swiper-item>
		</swiper>
		<!-- 中间icon图标 -->
		<view class="icon-container">
			<!-- 每个icon-row里循环 -->
				<view class="icon-row" >
					<view class="icon-item" >
						<!-- icon图标 -->
						<image src="" class="icon-image"></image>
						<!-- 底部文字 -->
						<text class="icon-text"></text>
					</view>
				</view>
		</view>
		<!-- 热门文章 -->
		<view class="article">
			<view style="display: flex;justify-content: space-between;margin: 0 50rpx;">
				<text style="font-weight: bold;">热门文章</text>
				<text style="font-size: 12px;color:#ccc">查看全部></text>
			</view>
			<!-- 文章内容 -->
			<view class="article-img"  >
				<!-- 文章图片 -->
				<img src="" alt="" class="img"/>
				<!-- 文章标题 -->
				<view class="hot-word">
					
				</view>
			</view>

		</view>
	</view>
</template>

<script>

	export default {
		data() {
			return {
				// 轮播图内容
				swiperItems: [
					{
						id:1,
						url:"https://img-blog.csdnimg.cn/2021051521244130.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl81MzQ0Nzc3Ng==,size_16,color_FFFFFF,t_70"
					},
					{
						id:2,
						url:"https://ts1.cn.mm.bing.net/th/id/R-C.9881613a29f26488b40938427aa585e4?rik=fim4XvDejjHE%2fQ&riu=http%3a%2f%2fn.sinaimg.cn%2fsinakd20220516ac%2f797%2fw2048h1149%2f20220516%2fb0aa-5aca29fe2dfa69c385118bbc74d039de.jpg&ehk=tzq%2bJP6uMipI0aIHY3bMSVO7lS7ZQM6TKMlwZ5CFP4s%3d&risl=&pid=ImgRaw&r=0"
					},
					{
						id:3,
						url:"https://ts1.cn.mm.bing.net/th/id/R-C.1ba7730f131b89278f37af053abd305c?rik=4ZdRDx%2bBrDRsgA&riu=http%3a%2f%2fpic.bizhi360.com%2fbbpic%2f90%2f10190.jpg&ehk=BEPnflW%2bZdQGggy286CG%2bpJrPop%2b92UEVILUX%2bnbV18%3d&risl=&pid=ImgRaw&r=0"
					}
				],
				// 字体图标内容
				iconRows: [
					{		id:1,
							url: '/static/icon1.png',
							text: '添加文章',
							path:'/pages/article/article'
						},
						{
							id:2,
							url: '/static/icon.png',
							text: '代码帮助'
						},
						{
							id:3,
							url: '/static/call.png',
							text: '联系我们'
						},
						{
							id:4,
							url: '/static/liuyan.png',
							text: '我要留言'
						}
				],
				// 热门文章内容
				hotWord:{
					text:"标题",
					img:"http://contentcms-bj.cdn.bcebos.com/cmspic/96bfd5a4a25940d636812bae6737697d.jpeg?x-bce-process=image/crop,x_0,y_0,w_1597,h_877"
				},
				hot_list:[]
			}
		},
		onLoad() {
			
		},
		methods: {
			
		}
	}
</script>

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

	.swiper-container {
		width: 90%;
		/* 针对于移动端小程序专门用的单位 */
		height: 300rpx;
		margin: 0 auto;
		/* 根据需要调整高度 */
	}

	.swiper-image {
		width: 100%;
		height: 100%;
		object-fit: cover;
	}

	.icon-container {
		width: 100%;
		margin: 50rpx 0;
		display: flex;
		align-items: center;
	}

	.icon-row {
		flex: 1;
		margin-bottom: 20rpx;
	}

	.icon-item {
		display: flex;
		flex-direction: column;
		align-items: center;
	}

	.icon-image {
		width: 80rpx;
		height: 80rpx;
	}

	.icon-text {
		margin-top: 10rpx;
		font-size: 24rpx;
		color: #8f8f94;
	}

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

	.title {
		font-size: 36rpx;
		color: #8f8f94;
	}

	.article {
		width: 100%;
	}
	.article-img{
		width: 100%;
	}
	.img{
		margin:50rpx 50rpx 10rpx 50rpx;
		width: 650rpx;
		height: 400rpx;
	}
	.hot-word{
		margin-left: 50rpx;
	}
</style>

文章列表页初代码,静态图片自己加入。:

html 复制代码
<template>
	<view class="content">
		<!-- 每一个文章卡片,在这里循环 -->
		<view class="index-card" >
			<!-- 封面 -->
			<image class="index-img" src="" mode=""></image>
			<view class="ellipsis">
				<!-- 文章标题 -->
				<text>
				
				</text>
			</view>
			<!-- 文章时间 -->
			<view class="index-small">
				
			</view>
		</view>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				listData: [{
						title: "暴走萝莉·金克丝,是MOBA竞技网游《英雄联盟》中的英雄角色,定位为射手。",
						img: "/static/img1.jpg",
						id: 1,
						content: '是英雄联盟历史上第一个拥有宣传视频的英雄。\n金克丝在团战初期就能输出大量伤害。金克丝的攻击距离以及伤害使得她能够与远距离poke型阵容融合。\n 神经狂躁、冲动任性、劣迹斑斑......金克丝出身自祖安,生来就爱不计后果地大搞破坏。她就是一座人形自走军火库,所经之处必定会留下夺目的火光和震耳的爆炸。金克丝最讨厌无聊,所以不管她去到哪里,混乱和骚动就会如期而至,这就是她留下的"到此一游"。'
					},
					{
						title: "逆羽·霞,是MOBA竞技网游《英雄联盟》中的一位英雄角色,是一个极具输出与收割能力的射手英雄",
						img: "/static/img2.jpg",
						id: 2,
						content: '她能凭借着具有穿刺效果的羽毛,同时对敌方前排与后排造成大量伤害。霞最擅长的就是使用羽毛,合理的运用羽毛的停留,能让她收获出乎意料的效果。 \n 身为瓦斯塔亚的志士,霞要掀起一场革命来拯救她的族群。她身法敏捷又慧心独具,凭借锋芒逼人的羽刃,扫除任何异己。霞与她的灵魂伴侣洛并肩作战,共同守护他们日渐衰落的部族,同时韬光养晦,希望终有一天能率领全族重夺昔日荣光.'
					},
					{
						title: "封魔剑魂·永恩,是MOBA竞技网游《英雄联盟》中第150位登场的英雄角色,英雄定位为战士、刺客",
						img: "/static/img3.jpg",
						id: 3,
						content: '生前的永恩,恪守着忠义师道。从很小的时候,他就开始为心爱的家庭扮演保护者的角色,不得不说这很大程度上是因为幼年丧父对他的影响。与他形成鲜明对比的,是他同母异父的弟弟------亚索。与亚索的冲动、鲁莽相反,永恩充满了耐心和自律。\n 生前,他是永恩,是亚索同母异父的哥哥,是故乡剑术道场的知名弟子。但当他死在弟弟手下以后,却发现自己被精神领域中的恶毒灵体所侵扰,不得不用它自己的刀剑将它弑杀。如今,被诅咒的永恩戴上了它的恶魔面具,开始了不懈的追猎,他要猎尽所有同种的恶魔,从而查清自己究竟成为了什么。'
					},
					{
						title: "刀锋舞者·艾瑞莉娅,是MOBA竞技网游《英雄联盟》中的英雄角色,定位为战士。",
						img: "/static/img4.jpg",
						id: 4,
						content: '时而似平静的海面,时而似汹涌的风暴。艾瑞莉娅是艾欧尼亚勇猛的捍卫者,她接受过祖辈传承的舞蹈训练,并将舞艺化为战斗的技法。伴随着她优雅的动作,锋利的刀刃在空中组成夺命的阵列翩翩起舞,这位刀锋舞者将斩除任何想要扮演征服者的蠢货。\n 诺克萨斯对艾欧尼亚的占领催生了许多英雄,但没有谁像纳沃利的艾瑞莉娅一般令人意外。她将家乡的古老舞艺化为战技,以精心修习的优雅身姿操控着致命的刀丛。在她证明了自己的战斗实力后,被众人推举为反抗军的领袖和首脑,为了守卫家园而奋斗至今。'
					},
					{
						title: "探险家·伊泽瑞尔,是MOBA竞技网游《英雄联盟》中的一名英雄角色,定位为射手、法师",
						img: "/static/img5.jpg",
						id: 5,
						content: '伊泽瑞尔是一名非常灵活飘逸的英雄,双加成的技能使他不但可以走AD路线,也能作为法师走AP路线。\n 神采奕奕的冒险家伊泽瑞尔拥有自己不知道的魔法天赋,他搜刮失落已久的古墓,触碰古老的诅咒,还举重若轻地挑战常人不可能完成的极限。他的勇气和壮举无边无际,总是喜欢随机应变地解决任何情况,一定程度上依赖他的小聪明,但更主要是依赖他神秘的恕瑞玛护手,在他的操控下释放出破坏性的奥术爆弹。有一件事可以肯定------只要伊泽瑞尔出现,那么麻烦一定接踵而至。或是还没走远。范围大概是随时随地。'
					}
				]
			}
		},
		onLoad() {

		},
		methods: {

		}
	}
</script>

<style>
	.content {
		width: 90%;
		margin: 0 auto;
	}

	.index-card {
		width: 100%;
		height: 500rpx;
		margin-bottom: 10rpx;
	}

	.index-img {
		width: 100%;
		height: 400rpx;
		border-radius: 15rpx 15rpx 0rpx 0rpx;
	}

	.ellipsis {
		padding: 0 10rpx;
		white-space: nowrap;
		/*超出的空白区域不换行*/
		overflow: hidden;
		/*超出隐藏*/
		text-overflow: ellipsis;
		/*文本超出显示省略号*/
		margin-bottom: 5rpx;
	}

	.index-small {
		text-align: right;
		font-size: 14px;
		color: #cfccc9;
	}
</style>

首先是我们的

轮播图:

相关代码我们可以从官网的swipe中找到案例:

我们的每一个相片都是一个swipe-item。

我们所有的相片地址都写在了export default里面了,所以我们接下来使用v-for来调用我们数组里面的元素。

接下来是我们下面的

功能图标:

是我们的数组里嵌套对象,我们接着用v-for调用元素。

然后是

热门文章:

因为我们先写的是假数据(死数据),我们渲染的话是用我们渲染对象的方式

假数据:就是提前写好的,一般于我们的用户没有交互的数据内容。

我们接下来给我们的查看全部设置点击事件:

<text style="font-size: 12px;color:#ccc" @click="toText">查看全部></text>

html 复制代码
			toText(){
				uni.navigateTo({
					url: '/pages/text/text',
				});
			}
			

然后利用v-for调死数据就可以完成我们的文章列表页的渲染(时间函数暂时未写):


动态数据

与后端的交互模式,一般是我们向后端发送请求,然后后端给我们返还相应的指令,我们再检查指令是否是我们想要的,如果是我们就使用。

我们的网络请求如下,我们使用的是Axios,其是Ajax的二次开发。

首先需要

安装的俩个库:

pip install flask

pip install flask_cors

request.js和api.js源码

首先我们的Ajax请求封装在了,request.js里面,代码如下:

html 复制代码
// const baseUrl = 'http://127.0.0.1:5005' /* 根域名 */
// const baseUrl = 'http://192.168.1.167:5005'
// 动态配置根域名 main.js
const baseUrl = uni.getStorageSync('rootDomain5000')
// const baseUrl = uni.getStorageSync('rootDomain5005')
// const baseUrl = uni.getStorageSync('rootDomain')
const request = (url = '', options = {}, contentType = 'application/json') => {
  return new Promise((resolve, reject) => {
    uni.showLoading({
      title: '加载中',
      mask: true,
    })
	// let baseUrl = url.includes('/login') ? rootDomain5005 : rootDomain5000
	// console.log(rootDomain5005,'111')
    uni
      .request({
        method: options.method,
        url: baseUrl + url,
        data: options.data,
        header: {
          'Content-Type': contentType,
          Authorization: uni.getStorageSync('token'),
        },
        dataType: 'json',
      })
      .then((response) => {
        uni.hideLoading()
        let {
          statusCode,
          data,
          errMsg
        } = response
        if (statusCode === 200) {
          resolve(data)
        } else {
          uni.showToast({
            title: errMsg,
            icon: 'none',
          })
          reject(errMsg)
        }
      })
      .catch((error) => {
        reject(error)
      })
  })
}
const get = (url, data) => {
  return request(url, {
    method: 'GET',
    data: data,
  })
}

const post = (url, data) => {
  return request(url, {
    method: 'POST',
    data: data,
  })
}

const postQuery = (url, data) => {
  return request(
    url, {
      method: 'POST',
      data: data,
    },
    'application/x-www-form-urlencoded'
  )
}

const put = (url, data) => {
  return request(url, {
    method: 'PUT',
    data: data,
  })
}

module.exports = {
  get,
  post,
  postQuery,
  put,
}

然后api.js里面装着我们的接口。

代码如下:

html 复制代码
const requests = require('@/utils/request.js')

// 登录接口
export const loginGet = (param) => {
  return requests.get('/loginxcx', param)
}

// 首页轮播图
export const home_switch = () =>{
	return requests.get('/switch',)
}

// 文章列表
export const listShow = (param) => {
  return requests.get('/article_list', param)
}

// 获取文章详情
export const article_details = (id) => {
  return requests.get(`/article_details?id=${id}`)
}

// 添加文章
export const add_article = (data) => {
  return requests.post(`/add_article`,data)
}

我们所有的Ajax请求全部写在我们的request.js里面,所以在接口文件里面,我们仅需要去调用request里面的Ajax请求就可以了。

小知识:

如果另一个文件需要调用该文件,该文件需要导出,另一个文件需要导入。

然后我们来介绍

api的结构:

request先不用管,因为大多数小程序,该后端代码依旧适用。

const是定义变量的关键词。

箭头函数导出的固定形式:

export const 函数名 = (形参)=> {

return requests.get(导出的文件地址,形参)

注意:我们的请求方式,参数等都是需要严格和后端代码相对于,否则会报错。

在app.py中我们可以看到我们的后端代码:

现在我们来启动一下后端代码:

直接运行app.py,然后它就在后台运行了。

1,用后端代码运行轮播图。

所以,我们现在index里面导入该文件

@/表示在根目录,及我文件的my_Blog,这样会方便写我们的相对路径。

先导入我们的函数:import { home_switch } from '@/pages/apis/api.js'

注意:该导入位置与我们的export default平行。

我们的下方去调用它:

getSwiper()

{

home_switch().then((res)=>{

console.log(res);

})

}

注意我们的写法,home_switch().then()语法,是说当我们调用了前者函数,就执行我们then后面括号里面的内容,然后上面是我们then后面又写了一个箭头函数。注意,我们res如果只有一个参数,括号可以省略。

然后我们操作一下

非手动点击的函数调用。(进入则调用)

我们的onLoad函数就是这样的功能:

一进入页面就执行onLoad函数,所以我们在onLoad函数里面调用 getSwiper(),就可以打印出来res里面的信息了。(调用要用this哦!!!)

调用后,我们的res内容是: 而我们需要其中的data里面的数据,这个data里面的内容也恰好与我们的轮播图数组里面的内容结构一致,那么我们就可以直接使用res.data去调用我们的后端活数据(来源于数据库),不去用死数据了。

2,后端代码导入文章列表页。

与上述同样的方式,我们在文章列表页重新操作一次: 便可得到我们想要的结果。

我们可以等于(第9行)的原因是俩者结构完全相同。

time的实时化

{{ item.time}}调用即可。

3,添加文章事件的点击事件。

因为我们的图标是以循环的方式添加的,所以我们添加点击事件就是给每一个图标都添加点击事件。而且我们也不能跳转到同一个页面。

我的的图标结构如下: 所以我们的uni.navigateto中的url不能写死,需要往函数里面传参,就是path

函数的构建: -------->点击事件的创建。

然后就完成了点击事件。

那现在我们的任务就是给我们的添加文章页面添加功能,使其能够将数据传输到我们的后端接口,完成文章的添加。

先设置容器,保存我们的数据:

然后再去设置点击事件。


(1)表单控件的数据绑定:

指令:v-model 双向数据绑定:在输入框里面修改的内容在下方里面的title等里面的内容也会跟着进行改变。 写在input里面.

比如:


我们给title和content绑定了数据后: 再去考虑选择图片按钮。使其能够打开本地图片并且选择

(2)选择本地图片并上传
步骤一:打开相册,选择图片。

关于相关代码,可以在官网寻找:

相关的属性:

我们对示例进行修改后,便可进行修改。其中res的内容是:

"0":是我们的本地临时路径,只能在本地访问,浏览器无法访问。这也是我们上传的文件的本地路径。但我们需要把这个图片理由后端存到某个地方(一般是服务器),我们没有服务器,所以我们目前操作是把我们的本地图片传给后端文件,然后将该图片文件存储到我们的本地数据库里。

步骤二:上传图片

我们仿照如下示例进行操作:

真实后端接口= 后端启动IP + 上传图片的接口名 。这里我们后端的接口名是upload_img

打印一下我们的success回调函数后,可以发现,我们的图片地址在后端发生了地址的拼接,这个拼接后的地址,就是我们将文件存入后,所在的后端服务器地址,我们需要获得他

打印回调函数里面的data后发现其是一个字符串(如果是对象,则是可折叠的)

我们需要对其进行进行转化,

语法JSON.parse(转换的对象)

转换成功:

我们需要的地址是其中的data。

所以我们写 let realpath = data.data 就可以了。

步骤三:图片回显

注意:如果我们想要在函数里面使用this ,我们的函数必须是箭头函数,否则我们的下面无法访问this里面的对象。

整体函数如下。

html 复制代码
		handleImg(){
			    uni.chooseImage({
				count: 1, 
				sizeType: ['original', 'compressed'], 
				sourceType: ['album'], //从相册选择
				success: res =>{
							const path = res.tempFilePaths[0]
							uni.uploadFile({
							url: 'http://127.0.0.1:5000/upload_img', //仅为示例,非真实的接口地址
							filePath: path,
			     				name: 'file',
			    				success: (uploadFileRes) => {
							// uploadFileRes.data是一个json字符串,我们需要进行转换
								let data = JSON.parse(uploadFileRes.data)
			     				this.img=data.data
								let real_path = data.data
								// 将图片回显
								this.img = real_path
								
							}
						});
				}
			});
步骤四:完成文章的添加

在我们导入函数后调用时,出现了以下的报错。

原因是:我们的后端代码是带参数的,所以我们需要给我们的函数传参。

----》 文章添加成功

我们的参数也可以在外面用变量包括,然后参数写对象就行了。

现在我们设置点击添加文章后返回首页就可以了。

但是我们的首页在tab-bar里面,所以,我们需要更改跳转方式:

因为我们的页面值更改了一次,所以我们可以选择:

uni.navigateBack(OBJECT) 或者: uni.switchTab(OBJECT) ---这个是通用情况

将其处理好之后,我们就完成了文章的添加。

相关推荐
编程猪猪侠24 分钟前
Tailwind CSS 自定义工具类与主题配置指南
前端·css
qhd吴飞28 分钟前
mybatis 差异更新法
java·前端·mybatis
YGY Webgis糕手之路1 小时前
OpenLayers 快速入门(九)Extent 介绍
前端·经验分享·笔记·vue·web
患得患失9491 小时前
【前端】【vueDevTools】使用 vueDevTools 插件并修改默认打开编辑器
前端·编辑器
ReturnTrue8681 小时前
Vue路由状态持久化方案,优雅实现记住表单历史搜索记录!
前端·vue.js
UncleKyrie1 小时前
一个浏览器插件帮你查看Figma设计稿代码图片和转码
前端
遂心_1 小时前
深入解析前后端分离中的 /api 设计:从路由到代理的完整指南
前端·javascript·api
你听得到111 小时前
Flutter - 手搓一个日历组件,集成单日选择、日期范围选择、国际化、农历和节气显示
前端·flutter·架构
风清云淡_A1 小时前
【REACT18.x】CRA+TS+ANTD5.X封装自定义的hooks复用业务功能
前端·react.js
@大迁世界1 小时前
第7章 React性能优化核心
前端·javascript·react.js·性能优化·前端框架