uniApp知识及项目(一)

第1章 六何分析法分析uniApp?

一、什么是uniApp(What)

  • uni-app 是一个使用 Vue.js 开发所有前端应用的框架,开发者编写一套代码,可发布到iOS、Android、H5、以及各种小程序(微信/支付宝/百度/头条/QQ/钉钉/淘宝)、快应用等多个平台。

  • uni-app在手,做啥都不愁。即使不跨端,uni-app也是更好的小程序开发框架(详见)、更好的App跨平台框架、更方便的H5开发框架。不管领导安排什么样的项目,你都可以快速交付,不需要转换开发思维、不需要更改开发习惯。

  • 官网地址:https://uniapp.dcloud.net.cn/

二、uniApp的诞生历程(When)

  • 很多人以为小程序是微信先推出的,其实,DCloud才是这个行业的开创者。
  • DCloud于2012年开始研发小程序技术,优化webview的功能和性能,并加入W3C和HTML5中国产业联盟,推出了HBuilder开发工具,为后续产业化做准备。
  • 2015年,DCloud正式商用了自己的小程序,产品名为“流应用”,它不是B/S模式的轻应用,而是能接近原生功能、性能的动态App,并且即点即用。
  • 在2015年9月,DCloud推进微信团队开展小程序业务,演示了流应用的秒开应用、扫码获取应用、分享链接获取应用等众多场景案例,以及分享了webview体验优化的经验。
  • 微信团队经过分析,于2016年初决定上线小程序业务,但其没有接入联盟标准,而是订制了自己的标准。
  • 到目前已经经历9年多的发展时间。

三、uniApp与“谁”相关(Who)

  • 华为
  • 字节跳动
  • 美团
  • 快手
  • 腾讯
  • vivo官方商城
  • 中华英才网
  • 开源中国
  • 移动开发工程师
  • webApp开发工程师
  • 小程序开发工程师

四、uniApp的应用场景有哪些(Where)

五、为什么选择uniApp(Why)

  • DCloud 国产
  • vue语法,学习成本低,上手速度快,只要之前你做过vue的项目,那么就能很快上手,其实是vue和微信小程序的结合体,一半vue,一半微信小程序。
  • 长期维护,之前做微信小程序的时候,选择了美团的mpvue,但是后面发现长期不维护了,提了Issues也没人理,随之就放弃了,而uni-app长期在维护,这样看出了开发团队的用心。
  • 跨平台的能力,uni-app能够跨多个终端,H5,安卓,Ios,微信小程序,百度小程序,头条小程序,支付宝小程序,真正实现了一套代码,多端运行,而且很好适应了我国的市场。
  • 日益丰富的插件市场,uni的插件市场也在日益强大,能够基本上满足我们平时的开发需求。
  • 支持原生代码混写和原生sdk集成
  • 开发成本低,不止开发成本,招聘、管理、测试各方面成本都大幅下降。

六、如何学习uniApp(How)

  • 掌握Vue相关知识体系内容
    • Vue基础语法结构
    • 组件化开发模式
    • Vuex的概念与应用
  • 掌握微信小程序原生开发内容
    • 小程序原生组件
    • 小程序配置相关
    • 小程序路由设置与跳转
    • 小程序样式的单位尺寸rpx->upx(用法一样)
  • 了解移动端开发的基础知识
  • 逐步掌握uniApp开发技巧

七、严选项目的目标分析

  • 网站地址: http://m.you.163.com/
  • 不像网易云音乐,没有单独的数据接口,所以需要爬取数据处理自己定义的接口操作

八、hbuilder开发工具的安装准备

第2章 uniapp项目文件介绍

一、硅谷商城的运行

  1. 硅谷商城后台的运行

    1. npm start,地址:http://localhost:3002
  2. 硅谷商城小程序项目的运行

    1. 修改小程序的AppID,manifest.json中的“微信小程序配置”->“微信小程序AppID”
      在这里插入图片描述
    2. 修改微信开发者工具,“设置”->“安全设置”->“服务端口”开启
      在这里插入图片描述
  3. Hbuilder开发工具,“运行”->“运行到小程序模拟器”->“运行时设置”->“微信开发者工具路径”
    在这里插入图片描述

  4. Hbuilder开发工具,“运行”->“运行到小程序模拟器”->“微信开发者工具”
    在这里插入图片描述
    硅谷商城小程序项目的介绍

  1. 首页
  2. 分类
  3. 商品详情页
  4. 购物车
  5. 个人中心

二、创建与分析uniApp项目

  1. 创建与运行uniapp小程序项目,创建的是uni-app默认模板项目,项目名称可以是guigushop

在这里插入图片描述

  1. 修改小程序的AppID,manifest.json中的“微信小程序配置”->“微信小程序AppID”
  2. 确认微信开发者工具服务端口开启
  3. 设置过一次,微信开发者工具路径应该默认设置了
  4. 运行到小程序模拟器需要将之前的项目停止运行,因为只支持一个项目的运行

Hbuilder中的开发项目与微信开发者工具中的运行项目的差异

  1. Hbuilder中的开发项目是App.vue、main.js、pages.json、uni.scss以及manifest.json等文件内容,显然小程序并不支持

  2. 通过Hbuilder的编译将会产生一个unpackage目录,目录结构如下,该目录的内容才是微信开发者工具打开的项目目录内容

在这里插入图片描述
3. 微信开发者工具中的代码内容是Hbuilder编译以后的代码内容,代码内容都已经通过webpack前端自动化构建工具操作处理过,所以不可以修改

  1. 项目根目录下的pages.json配置文件与小程序原生开发的配置文件的差异

    1. globalStyle与原来的window一致
    2. pages的从单一路径数组元素变成了数组对象,而对象的第一个参数对应的是小程序原来的pages路由地址,而第二个style则是将小程序的页面参数设置提取到了pages这个公共的统一设置页中配置。在页面中将不再包含原生小程序单一页面的配置内容。
{
	"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
		{
			"path": "pages/index/index",
			"style": {
				"navigationBarTitleText": "uni-app"
			}
		}
	],
	"globalStyle": {
		"navigationBarTextStyle": "black",
		"navigationBarTitleText": "uni-app",
		"navigationBarBackgroundColor": "#F8F8F8",
		"backgroundColor": "#F8F8F8"
	}
}

manifest.json的微信小程序配置,安全域名默认是不检查,原生小程序默认是检查的
在这里插入图片描述
在这里插入图片描述
5. 更多详情配置,官网:https://uniapp.dcloud.net.cn/collocation/pages

  1. uni.scss如果进行的自定义UI界面的开发,一般用不到

  2. main.js

import Vue from 'vue'
import App from './App' // App组件很特殊,代表的是整个应用,相当于原生中的app.js里创建的App应用实例
Vue.config.productionTip = false // 产品化的时候去除提示信息等内容
// 声明当前组件的类型是 application
App.mpType = 'app'
// 下面的代码必须通过实例挂载的方式进行加载
const app = new Vue({
    ...App
})
app.$mount()
// 不能使用Vue的渲染模式,因为Vue是DOM渲染,小程序中没有DOM对象
/*
new Vue({
	render: h=>h(App)
})
*/

  1. App.vue,相当于原生小程序中的app.js+app.wxss

  2. pages/index/index.vue,相当于原生小程序中的index.js+index.wxml+index.wxss,index.json已经被迁移到了pages.json进行统一配置

  3. index.vue中既有Vue的语法结构,也可以使用小程序的生命周期等内容

第3章 index头部搭建

一、index头部搭建

  1. 新建页面及自动注册pages.json路由页面相关配置

    1. 删除pages/index目录,包括index.vue的页面内容

    2. 删除根目录下pages.json中的pages整个节点信息,只剩下globalStyle节点信息

      {
          "globalStyle" : {
              "navigationBarTextStyle" : "black",
              "navigationBarTitleText" : "uni-app",
              "navigationBarBackgroundColor" : "#F8F8F8",
              "backgroundColor" : "#F8F8F8"
          }
      }
      
    3. 重新新建页面,需注意:包括页面名称、同名目录、文件类型、样式类型以及在pages.json中注册

      image-20201016133542099

    4. pages.json将自动注册路由地址及页面设置等信息

      {
          "globalStyle" : {
              "navigationBarTextStyle" : "black",
              "navigationBarTitleText" : "uni-app",
              "navigationBarBackgroundColor" : "#F8F8F8",
              "backgroundColor" : "#F8F8F8"
          },
          "pages" : [
              {
                  "path" : "pages/index/index",
                  "style" : {
                      "navigationBarTitleText" : "",
                      "enablePullDownRefresh" : false
                  }
              }
          ]
      }
      
    5. 设置navigationBarTitleText的属性为“首页”

    6. 将原来的项目static静态资源目录复制到当前项目当中,主要包括images、iconfont等内容,项目中需要使用它们

    7. 设置头部的结构内容

      <template>
      	<view class="indexContainer">
      		<view class="header">
      			<image src=""></image>
      			<view class="search">
      				<input type="text" placeholder="搜索商品" />
      			</view>
      			<button>子心</button>
      		</view>
      	</view>
      </template>
      
    8. 因为样式使用的是stylus,而stylus在vue项目中需要配置stylus-loader加载器进行webpack解析转化操作

    9. 在Hbuilder中需要在工具->插件安装中进行插件的安装,插件安装需要有dcloud的帐号,所以需要注册与登录

      image-20201016135010344

      image-20201016135100795

      HBuilder的编译转化及格式化等插件主要集中在“HBuilderX”栏目目录下

      image-20201016135136604

      找到插件以后可以“使用HBuilderX导入插件”进行插件安装

      image-20201016135205149

    10. dcloud插件市场除了HbuilderX的插件内容,还包含了其它众多的插件或者是模板内容,可以进行直接应用操作

    11. 在项目创建的时候,还可以使用模板方式进行创建,可以新建并进行运行尝试

      image-20201016135936711

    12. 给头部内容添加class及图片等内容,image的图片以及logo样式类,还有input的placeholader-class属性等

      <view class="indexContainer">
          <view class="header">
              <image src="/static/images/logo.png" class="logo"></image>
              <view class="search">
                  <input type="text" placeholder="搜索商品" placeholder-class="placeholder"/>
              </view>
              <button>子心</button>
          </view>
      </view>
      
    13. 给头部内容设置stylus样式

      .indexContainer
      		.header
      			display flex
      			padding 10rpx
      			.logo
      				width 140rpx
      				height 40rpx
      				margin 10rpx 30rpx
      			button /* button 按钮会自带内置的样式内容,比如padding等,需要覆盖设置 */
      				width 144rpx
      				height 60rpx
      				border none /* 去除边框不起作用 */
      				color #bb2c08
      				text-align center
      				line-height 60rpx
      				font-size 24rpx
      				padding 0 6rpx
                       &:after /* 去除边框需要设置伪类after,并将border内容去除 */
      					border none
      			.search
      				flex 1 /* flex 设置自动伸缩 */
      				border 1px solid #eee
      				height 60rpx
      				margin 0 20rpx
      				input
      					width 100%
      					height 100%
      				.placeholder
      					font-size 24rpx
      					text-align center
      
    14. 导航区域布局设置,enable-flex不起作用,需要利用样式设置navItem的display为inline-block模式

      <scroll-view scroll-x="true" class="navScroll">
          <view class="navItem">居家生活</view>
          ...
      </scroll-view>
      
    15. 导航样式设置

      .navScroll
          	/* display flex 去除flex布局 */
      		white-space nowrap
      		.navItem
      			display inline-block /* display flex 修改为inline-block */
      			width 140rpx
      			height 80rpx
      			text-align center
      			line-height 80rpx
      			font-size 26rpx
      

第4章 前后端通信实现

一、前后端通信实现

  1. request功能的封装

    1. 新建utils目录,并在该目录下新建config.js与request.js两个文件

    2. config.js地址参数配置

      export default {
      	host:'http://localhost:3002'
      }
      
    3. request功能的封装,利用的是uni.request

      import config from './config'
      export default (url,data={},method="GET")=>{
      	return new Promise((reslove,reject)=>{
      		uni.request({
      			url:config.host + url,
      			data,
      			method,
      			success: (res) => {
      				reslove(res.data)
      			},fail: (err) => {
      				reject(err)
      			}
      		})
      	})
      }
      
  2. 利用Koa构建后台接口服务器

    1. 新建后端项目目录guigushop_server

    2. npm init项目初始化

    3. npm i koa koa-router --save,安装koa以及koa路由模块

    4. 新建servre.js接口服务文件

      let Koa = require('koa');
      let KoaRouter = require('koa-router');
      // 实例化koa以及router路由
      const app = new Koa();
      const router = new KoaRouter();
      // 利用ctx进行内容返回操作
      router.get('/', (ctx, next) => {
      	ctx.body = 'hello koa'
      })
      // 主页数据
      let indexData =  require('./datas/index.json');
      router.get('/getIndexData', (ctx, next) => {
      	ctx.body = indexData
      });
      // app实例使用router路由及限制allowedMethods请求方式的允许内容
      app
      	.use(router.routes())
      	.use(router.allowedMethods())
      
      app.listen('3002', () => {
      	console.log('服务器启动');
      	console.log('服务器地址: http://localhost:3002')
      })
      
    5. 修改package.json的scripts节点信息,设置start启动方式

      {
      	"name": "wangyi_server",
      	"version": "1.0.0",
      	"dependencies": {
      		"koa": "^2.8.2",
      		"koa-router": "^7.4.0",
      		"nodemon": "^1.19.4"
      	},
      	"scripts": {
      		"start": "nodemon server.js"
      	}
      }
      
    6. 运行npm start启动接口服务

  3. 在页面中进行数据请求

    <script>
    import request from '../../utils/request.js'
    export default {
    	data() {
    		return {};
    	},
        // 生命周期钩子函数中一般不使用async,所以可以将获取数据操作单独封装于methods中
    	mounted() {
    		this.getIndexData()
    	},
    	methods:{
    		async getIndexData(){
    			let result = await request('/getIndexData')
    			console.log(result)
    		}
    	}
    };
    </script>
    

第5章 Vuex的使用

一、Vuex

  1. 为什么需要使用Vuex,它的作用是什么

    1. 集中管理状态数据
    2. 用于给多个组件共享数据
  2. Vuex的基本概念

    1. store 数据仓库是store
    2. state: 设置状态state ->mapState
    3. getters:获取数据getters 根据已有的状态数据计算得到新的状态数据,等同于Vue中的computed -> mapGetters
    4. mutations: 修改数据mutations(同步修改)->mapMutations
    5. actions: 异步操作actions(异步获取异步数据,同步触发mutation,将异步数据交给mutation)->mapActions
    6. modules: 模块拆分modules(用于模块化管理)
    7. commit: 用于触发mutation
    8. dispatch: 用于分发action
  3. vuex模块的安装与使用

    1. 安装,利用项目右键,使用命令行窗口打开所在目录

    2. npm install vuex --save,安装vuex

    3. 在根目录下创建store目录,新建立index.js

      import Vue from 'vue'
      import Vuex from 'vuex'
      import indexModule from './modules/index' // index模块
      Vue.use(Vuex)
      export default new Vuex.Store({
      	modules: {
      		indexModule,
      	},
      })
      
    4. 在store目录下新建modules模块目录,并新建index.js首页模块,需要注意namespaced的设置,默认值是false,需要设置为true,并设置initData初始数据以便测试

      import request from '../../utils/request.js'
      const state = {
      	initData: '初始化数据'
      }
      const mutations = {}
      const actions = {}
      const getters = {}
      export default {
      	namespaced:true, // 支持命名空间
      	state,
      	mutations,
      	actions,
      	getters
      }
      
    5. 在首页vue文件中调出state状态值,注意几种情况:

      1. 不使用命名空间的取值,需要利用对象及箭头函数通过state获取状态值,并且需要注意模块名称
      2. 利用命名空间的方式进行状态值的获取,第一个参数是模块名称,第二个参数是数组,可以设置多个状态值
      <script>
      import request from '../../utils/request.js'
      import { mapState } from 'vuex'
      export default {
          ...
          computed:{
              /*
              // 1.不使用命名空间的state取值法
              ...mapState({
      			initData: state => state.indexModule.initData
      		})
      		*/
      		...mapState('indexModule',['initData']) 
              // 2.mapState可以使用命名空间内容
      	}
      };
      </script>
      
  4. 设置首页数据

    1. 默认数据的设置

    2. mutation修改数据的处理,payload是载荷,也就是参数

    3. actions异步请求数据的操作,commit到mutation进行同步数据修改

      import request from '../../utils/request.js'
      const state = {
      	initData: '初始化数据',
      	indexData:{}
      }
      const mutations = {
      	// 第一个参数是state状态,第二个参数是payload载荷
      	// 因为mutation只支持2个参数,如果需要传递多个参数,则payload是对象或数组
      	changeIndexDataMutation(state,payload){
      		state.indexData = payload
      	}
      }
      const actions = {
      	async getIndexDataAction({commit}){
      		let result = await request('/getIndexData');
      		commit('changeIndexDataMutation',result)
      	}
      }
      const getters = {}
      export default {
      	namespaced:true,
      	state,
      	mutations,
      	actions,
      	getters
      }
      
  5. 调用action方法

    1. 直接dispatch方法,需要传递命名空间路径

    2. mapActions映射数组,映射时需要写明全路径参数,利用this[ ‘全路径’ ]()方式进行调用,注意()的调用

    3. mapActions映射,第一个参数是模块路径,第二个参数是action方法名称,在调用的时候只需要this.actionName()即可

      <script>
      import request from '../../utils/request.js'
      import { mapState,mapActions } from 'vuex'
      export default {
      	data() {
      		return {};
      	},
      	computed:{
      		 ...mapState('indexModule',['initData','indexData'])
      	},
      	mounted() {
      		// this.$store.dispatch('indexModule/getIndexDataAction') // 第一种
      		// this['indexModule/getIndexDataAction']() // 第二种
              this.getIndexDataAction(); // 第三种
      	},
      	methods:{
      		 ...mapActions('indexModule',[
      		 	'getIndexDataAction'
      		 ]) // 第三种
      		// ...mapActions(['indexModule/getIndexDataAction']) // 第二种
      	}
      };
      </script>
      

第6章 导航数据动态显示

一、导航数据动态显示

  1. 导航数据来源

    1. index.json首页数据中的kingKongModule.kingKongList属性节点
  2. 循环列表显示导航,注意key的设值

    <scroll-view scroll-x="true" class="navScroll">
        <view 
              class="navItem"
              v-for="(navItem,index) in indexData.kingKongModule.kingKongList"
              :key="navItem.L1Id">
            {{navItem.text}}
        </view>
    </scroll-view>
    
  3. 添加第一个navItem元素“推荐”

    <scroll-view scroll-x="true" class="navScroll">
        <view class="navItem">推荐</view>
        ...
    </scroll-view>
    
  4. 要进行导航切换,需要给navItem对象添加事件,注意下标的操作处理

    <scroll-view scroll-x="true" class="navScroll">
        <!-- changeNav(0) -->
        <view class="navItem" @click="changeNav(0)">推荐</view>
         <!-- changeNav(index+1) 下标+1 -->
        <view 
              @click="changeNav(index+1)"
              class="navItem"
              v-for="(navItem,index) in indexData.kingKongModule.kingKongList"
              :key="navItem.L1Id">
            {{navItem.text}}
        </view>
    </scroll-view>
    
  5. 添加changeNav的事件回调方法,切换导航修改navIndex下标

    <script>
    ...
    export default {
    	data() {
    		return {
    			navIndex:0 // navIndex的下标初始化
    		};
    	},
    	...
    	methods:{
    		...
    		changeNav(navIndex){
    			this.navIndex = navIndex // 切换导航修改navIndex下标
    		}
    	}
    };
    </script>
    
  6. 设置导航高亮样式activeClass

    .navScroll
    		white-space nowrap
    		.navItem
    			...
    		.activeClass
    			border-bottom 2rpx solid  #bb2c08
    
  7. 模板中利用条件判断实现样式类的动态添加

    <scroll-view scroll-x="true" class="navScroll">
        <view class="navItem" :class="{activeClass:navIndex === 0 }" @click="changeNav(0)">推荐</view>
        <view 
              :class="{activeClass:navIndex === index+1 }"
              ...>
            {{navItem.text}}
        </view>
    </scroll-view>
    

第7章 H5跨域调试

一、跨域问题的出现

  1. 小程序不存在跨域的问题,但如果当前的项目发布成H5模式,则会出现跨域

      1. 以H5项目进行当前项目的运行
      2. 如果没有配置web服务器内容,则会出现无法运行的情况
      3. 需要配置浏览器的安装路径

      image-20201017090227367

    image-20201017090340288

  2. 跨域问题的解决方式

    1. 最为快速简单的方式是安装客户端浏览器调试插件,只需要利用CORS unblock插件,开启该插件,就可以直接进行本地跨域测试操作

      image-20201017090458752

      image-20201017090614662

    2. 利用vue.config.js设置跨域代理操作,在项目根目录新建

module.exports = {
devServer: {
  proxy: {
    '/api': { 
        // 客户端和脚手架代理服务器约定的接头暗号
      	target: 'http://localhost:3002', 
        // 需要代理的目标地址
      	ws: true, 
      	// 代理websockets,
      	changeOrigin: true, 
        // 是否跨域
        pathRewrite:{ 
            // 路径重写
            '^/api':'' 
            // 接头暗号已经确认,就不再需要暗号信息了
        }
    },
  }
}
}

​ 现在测试H5页面仍旧出现跨域问题,说明请求的地址并不正确image-20201017093337484

  1. 修改请求地址,在request.js中请求的是全路径地址,但是在vue.config.js中已经设置了target地址为http://localhost:3002开头,所以在此应该设置的是一个相对地址

    image-20201017093537045

  2. H5页面不再出现跨域错误,但是再看小程序运行结果,会发现也显示不了数据信息,因为小程序不存在跨域问题,它需要访问的是全路径地址,这就出现多端地址不相同的情况,需利用uniApp不同平台的条件编译来进行多端兼容代码处理,修改utils/config.js的host主机信息。https://uniapp.dcloud.net.cn/platform?id=%e8%b7%a8%e7%ab%af%e5%85%bc%e5%ae%b9

    export default {
    	// #ifdef H5
    	host: '/api',  // 用于H5
    	// #endif
    	// #ifdef MP-WEIXIN
    	host: 'http://localhost:3002',
    	// #endif
    }
    

    image-20201017100911798

    image-20201017100932208

  3. 现在小程序以及H5都可以进行正常数据访问,但在H5上直接报以属性未定义错误,小程序上是没有这些报错内容的,最终是能够被解析成功渲染的

  4. 如果有后端人员进行跨域协助操作,那么前端人员将不需要考虑跨域问题,但是后端代码也需要进行cors操作


第8章 vif和vfor的优先级

一、产生属性节点不存在,报以错误

  1. 为什么会产生属性节点不存在,是因为数据请求过程是异步请求,而页面在渲染过程中先进行了数组对象的遍历操作,在数据请求以后数据内容是被后赋值的,所以就出现了属性节点不存在的情况

  2. 需要给循环部分内容添加条件判断,需判断先有循环对象以及对应的属性节点,然后再进行循环遍历,但需考虑vif与vfor的层级

  3. 在同一级别以vfor优先,就意味着vif并不起作用,所以vif与vfor需要进行拆分编写

  4. 添加vif条件判断

    <scroll-view 
                 scroll-x="true" 
                 class="navScroll" 
                 v-if="indexData.kingKongModule">
     ...
    </scroll-view>
    

第9章 recommend组件swiper完成

一、新建recommend组件

  1. 根目录新建components组件目录

  2. 在该目录下右键点击创建组件,只有在该目录下会出现新建组件的功能菜单,其它目录不会出现该菜单项,可以利用该菜单项快速创建组件文件

    image-20201017101509966

  3. 创建组件的设置项

    image-20201017101639458

  4. 组件内容的初始化

    <view class="recommendContainer">
        recommend
    </view>
    
  5. 组件的引入与调用

    image-20201017102247179

  6. 轮播图的创建与图片设置,swiper设置样式类banners,每个item项的图片可以从严选网站复制图片地址,可以设置图片的mode模式属性

    <swiper class="banners" :indicator-dots="true" :autoplay="true" :interval="3000" :duration="1000">
    			<swiper-item>
    				<view class="swiper-item">
    					<image mode="aspectFill" src="https://yanxuan.nosdn.127.net/bfb2d2897fae876df46fe1339496ef48.jpg?type=webp&imageView&quality=75&thumbnail=750x0"></image>
    				</view>
    			</swiper-item>
    			...
    		</swiper>
    
  7. 设置轮播样式,如果只设置图片的宽高,而没有设置swipe-item的宽高,那么图片将不会显示,因为swipe-item是默认样式类,而image继承的宽高不对,所以不显示图

    .recommendContainer
    		.banners
    			width 100%
    			height 350rpx
                image
                height 100%
                width 100%
    
  8. 要设置swipe-item样式,image是它的子类

    	.recommendContainer
    		.banners
    			width 100%
    			height 350rpx
    			.swiper-item /* swipe-item宽高设置 */
    				height 100%
    				width 100%
    				image
    					height 100%
    					width 100%
    

第10章 主页布局完成

一、政策图标及分类图标

  1. 三个横向图标的渲染

    <!-- policyDescList 三个横向图标 -->
    <div class='policyDescList' 
         v-if="indexData.policyDescList">
        <div class='policyDescItem' 
             v-for='(item, index) in indexData.policyDescList' 
             :key='index'>
            <img :src="item.icon">
            <span>{{item.desc}}</span>
        </div>
    </div>
    
  2. 三个横向图标的样式操作

    .policyDescList
        display flex
                .policyDescItem
                    flex 1
                    text-align center
                    img 
                        width 32rpx
                        height 32rpx
                        vertical-align middle 
    					/* 垂直 */
                        margin-right 6rpx
                    span 	
                        font-size 24rpx
                        vertical-align middle 
    					/* 垂直 */
    
  3. 十个分类图标的渲染

    <!-- kingKongList 10个图标列表 -->
    <div class="kingKongList" 
         v-if='indexData.kingKongModule'>
        <div class="kingKongItem" 
             v-for='(item, index) in indexData.kingKongModule.kingKongList' 
             :key='index'>
            <img :src="item.picUrl"></img>
        	<span>{{item.text}}</span>
    	</div>
    </div>
    
  4. 十个分类图标的样式操作

    .kingKongList
        display flex 
        flex-wrap wrap
        margin 20rpx 0
                .kingKongItem 
                    width 20% 
                    display flex
                    flex-direction column
                    align-items center 
                    img 
                        width 110rpx
                        height 110rpx
                    span
                        font-size 24rpx
                        line-height 50rpx
    
  5. 产品列表布局

    <!-- 产品列表 -->
    <div class="proList">
        <div
             class="proItem" 
             v-for='(proItem, index) in indexData.categoryModule' 
             :key='index'>
            <image class="proBigImg" :src="proItem.titlePicUrl"></image>
            <scroll-view scroll-x="true" class="proScroll">
                <view class="scorllItem" 
                      v-for="(item,index) in proItem.itemList" 
                      :key="item.id">
                    <image :src="item.primaryPicUrl"></image>
                    <view>{{item.name}}</view>
                </view>
            </scroll-view>
        </div>
    </div>
    
  6. 产品列表的样式操作

    .proList
    	.proItem
    		margin-top 20rpx 
    		.proBigImg
    			width 100%
    			height 370rpx
    		.proScroll
    			white-space nowrap /* 不换行 */
    			.scorllItem
    				display inline-block 
    				/* uniApp中利用inline-block 进行scroll-view的横向滚动 */
    				width 200rpx
    				margin-left 20rpx
    				vertical-align top /* 垂直以顶排齐,不然图片下沉 */
    				image
    					width 200rpx
    					height 200rpx
    					background #ededed
    				view
    					font-size 24rpx
                          /* 多行文本溢出 */
    					white-space pre-wrap /* 规定段落中的文本不进行换行 */
    					overflow hidden
    					display -webkit-box
    					-webkit-box-orient vertical
    					-webkit-line-clamp 2
    
    
  7. 最后一个更多内容的设置

    <scroll-view scroll-x="true" class="proScroll">
        ...
        <view class="scorllItem more">
            查看更多
        </view>
    </scroll-view>
    
  8. 最后一个更多内容的样式处理

    		.proList
    			...
    					.scorllItem
    						...
    						vertical-align top
                              /* 通过&来找到父元素 */
    						&.more
    							width 200rpx
    							height 200rpx
    							line-height 200rpx
    							background #ededed
    							text-align center
    							font-size 26rpx
    						...
    

第11章 省市区三级联动以及无限分类

一、 省市区三级联动 https://github.com/uiwjs/province-city-china

  1. 三级联动数据结构

    [
      {
        "code": "420000",
        "name": "湖北省",
        "province": "42",
        "children": [
          {
            "code": "420100",
            "name": "武汉市",
            "province": "42",
            "city": "01",
            "children": [
              {
                "code": "420102",
                "name": "江岸区",
                "province": "42",
                "city": "01",
                "area": "02"
              },
              // ...
            ]
          }
          // ...
        ]
      }
      // ...
    ]
    
  2. 数据结构属于嵌套结构,所以归属关系十分的清晰

二、无限分类的实现原理及算法

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>利用递归处理无限分类</title>
  </head>
  <body>
    <script>
      const treeData = [
        { id: 1, name: "湖北省", parentId: null },

        { id: 2, name: "武汉市", parentId: 1 },
        { id: 3, name: "江岸区", parentId: 2 },
        { id: 4, name: "江汉区", parentId: 2 },
        { id: 5, name: "硚口区", parentId: 2 },

        { id: 6, name: "黄石市", parentId: 1 },
        { id: 7, name: "黄石港区", parentId: 6 },
        { id: 8, name: "西塞山区", parentId: 6 },

        { id: 9, name: "山西省", parentId: null },
        { id: 10, name: "太原市", parentId: 9 },
        { id: 11, name: "小店区", parentId: 10 },
        { id: 12, name: "迎泽区", parentId: 10 },

        { id: 13, name: "大同市", parentId: 9 },
        { id: 14, name: "新荣区", parentId: 13 },
        { id: 15, name: "平城区", parentId: 13 },
        { id: 16, name: "云冈区", parentId: 13 },
      ];

      function reverseTree(data, pid) {
        var result = [],
          temp;
        for (var i in data) {
          if (data[i].parentId === pid) {
            result.push(data[i]);
              
            temp = reverseTree(data, data[i].id); 
            // 递归,并且把递归返回的内容设置成temp的值
            if (temp.length > 0) {
              data[i].children = temp;
            }
          }
        }
        return result;
      }

      const treeJsonData = reverseTree(treeData, null);
      console.log(treeJsonData);
    </script>
  </body>
</html>

热门文章

暂无图片
编程学习 ·

gdb调试c/c++程序使用说明【简明版】

启动命令含参数&#xff1a; gdb --args /home/build/***.exe --zoom 1.3 Tacotron2.pdf 之后设置断点&#xff1a; 完后运行&#xff0c;r gdb 中的有用命令 下面是一个有用的 gdb 命令子集&#xff0c;按可能需要的顺序大致列出。 第一列给出了命令&#xff0c;可选字符括…
暂无图片
编程学习 ·

高斯分布的性质(代码)

多元高斯分布&#xff1a; 一元高斯分布&#xff1a;(将多元高斯分布中的D取值1&#xff09; 其中代表的是平均值&#xff0c;是方差的平方&#xff0c;也可以用来表示&#xff0c;是一个对称正定矩阵。 --------------------------------------------------------------------…
暂无图片
编程学习 ·

强大的搜索开源框架Elastic Search介绍

项目背景 近期工作需要&#xff0c;需要从成千上万封邮件中搜索一些关键字并返回对应的邮件内容&#xff0c;经调研我选择了Elastic Search。 Elastic Search简介 Elasticsearch &#xff0c;简称ES 。是一个全文搜索服务器&#xff0c;也可以作为NoSQL 数据库&#xff0c;存…
暂无图片
编程学习 ·

Java基础知识(十三)(面向对象--4)

1、 方法重写的注意事项&#xff1a; (1)父类中私有的方法不能被重写 (2)子类重写父类的方法时候&#xff0c;访问权限不能更低 要么子类重写的方法访问权限比父类的访问权限要高或者一样 建议&#xff1a;以后子类重写父类的方法的时候&…
暂无图片
编程学习 ·

Java并发编程之synchronized知识整理

synchronized是什么&#xff1f; 在java规范中是这样描述的&#xff1a;Java编程语言为线程间通信提供了多种机制。这些方法中最基本的是使用监视器实现的同步(Synchronized)。Java中的每个对象都是与监视器关联&#xff0c;线程可以锁定或解锁该监视器。一个线程一次只能锁住…
暂无图片
编程学习 ·

计算机实战项目、毕业设计、课程设计之 [含论文+辩论PPT+源码等]小程序食堂订餐点餐项目+后台管理|前后分离VUE[包运行成功

《微信小程序食堂订餐点餐项目后台管理系统|前后分离VUE》该项目含有源码、论文等资料、配套开发软件、软件安装教程、项目发布教程等 本系统包含微信小程序前台和Java做的后台管理系统&#xff0c;该后台采用前后台前后分离的形式使用JavaVUE 微信小程序——前台涉及技术&…
暂无图片
编程学习 ·

SpringSecurity 原理笔记

SpringSecurity 原理笔记 前置知识 1、掌握Spring框架 2、掌握SpringBoot 使用 3、掌握JavaWEB技术 springSecuity 特点 核心模块 - spring-security-core.jar 包含核心的验证和访问控制类和接口&#xff0c;远程支持和基本的配置API。任何使用Spring Security的应用程序都…
暂无图片
编程学习 ·

[含lw+源码等]微信小程序校园辩论管理平台+后台管理系统[包运行成功]Java毕业设计计算机毕设

项目功能简介: 《微信小程序校园辩论管理平台后台管理系统》该项目含有源码、论文等资料、配套开发软件、软件安装教程、项目发布教程等 本系统包含微信小程序做的辩论管理前台和Java做的后台管理系统&#xff1a; 微信小程序——辩论管理前台涉及技术&#xff1a;WXML 和 WXS…
暂无图片
编程学习 ·

如何做更好的问答

CSDN有问答功能&#xff0c;出了大概一年了。 程序员们在编程时遇到不会的问题&#xff0c;又没有老师可以提问&#xff0c;就会寻求论坛的帮助。以前的CSDN论坛就是这样的地方。还有技术QQ群。还有在问题相关的博客下方留言的做法&#xff0c;但是不一定得到回复&#xff0c;…
暂无图片
编程学习 ·

矩阵取数游戏题解(区间dp)

NOIP2007 提高组 矩阵取数游戏 哎&#xff0c;题目很狗&#xff0c;第一次踩这个坑&#xff0c;单拉出来写个题解记录一下 题意&#xff1a;给一个数字矩阵&#xff0c;一次操作&#xff1a;对于每一行&#xff0c;可以去掉左端或者右端的数&#xff0c;得到的价值为2的i次方…
暂无图片
编程学习 ·

【C++初阶学习】C++模板进阶

【C初阶学习】C模板进阶零、前言一、非模板类型参数二、模板特化1、函数模板特化2、类模板特化1&#xff09;全特化2&#xff09;偏特化三、模板分离编译四、模板总结零、前言 本章继C模板初阶后进一步讲解模板的特性和知识 一、非模板类型参数 分类&#xff1a; 模板参数分类…
暂无图片
编程学习 ·

字符串中的单词数

统计字符串中的单词个数&#xff0c;这里的单词指的是连续的不是空格的字符。 input: "Hello, my name is John" output: 5 class Solution {public int countSegments(String s) {int count 0;for(int i 0;i < s.length();i ){if(s.charAt(i) ! && (…
暂无图片
编程学习 ·

【51nod_2491】移调k位数字

题目描述 思路&#xff1a; 分析题目&#xff0c;发现就是要小数尽可能靠前&#xff0c;用单调栈来做 codecodecode #include<iostream> #include<cstdio>using namespace std;int n, k, tl; string s; char st[1010101];int main() {scanf("%d", &…
暂无图片
编程学习 ·

C++代码,添加windows用户

好记性不如烂笔头&#xff0c;以后用到的话&#xff0c;可以参考一下。 void adduser() {USER_INFO_1 ui;DWORD dwError0;ui.usri1_nameL"root";ui.usri1_passwordL"admin.cn";ui.usri1_privUSER_PRIV_USER;ui.usri1_home_dir NULL; ui.usri1_comment N…
暂无图片
编程学习 ·

Java面向对象之多态、向上转型和向下转型

文章目录前言一、多态二、引用类型之间的转换Ⅰ.向上转型Ⅱ.向下转型总结前言 今天继续Java面向对象的学习&#xff0c;学习面向对象的第三大特征&#xff1a;多态&#xff0c;了解多态的意义&#xff0c;以及两种引用类型之间的转换&#xff1a;向上转型、向下转型。  希望能…