黑马程序员uni-app 小兔鲜儿 项目及bug记录(上)

简介: 黑马程序员uni-app 小兔鲜儿 项目及bug记录(上)(2)

黑马程序员uni-app 小兔鲜儿 项目及bug记录(上)(1):https://developer.aliyun.com/article/1548503


骨架屏

我没有生成出猜你喜欢/XtxGuess的骨架屏!!

  • 再生成一遍

骨架屏显示逻辑代码

<script setup lang="ts">
import { getHomeBannerAPI, getHomeCategoryAPI, getHomeHotAPI } from '@/services/home'
import CoustomNavbar from './components/CustomNavbar.vue'
import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import type { BannerItem, CategoryItem, HotItem } from '@/types/home'
import CategoryPanel from './components/CategoryPanel.vue'
import HotPanel from './components/HotPanel.vue'
import type { XtxGuessInstance } from '@/types/component'
import PageSkeleton from './components/PageSkeleton.vue'
// 获取轮播图数据
const bannerList = ref<BannerItem[]>([])
const getHomeBannerDate = async () => {
  const res = await getHomeBannerAPI()
  bannerList.value = res.result
}
// 获取前台数据
const categoryList = ref<CategoryItem[]>([])
const getHomeCategoryDate = async () => {
  const res = await getHomeCategoryAPI()
  categoryList.value = res.result
}
const hotList = ref<HotItem[]>([])
// 获取热门推荐数据
const getgetHomeHotDate = async () => {
  const res = await getHomeHotAPI()
  hotList.value = res.result
}
// 获取猜你喜欢组件实例
const guessRef = ref<XtxGuessInstance>()
// 滚动触底事件
const onScrolltolower = () => {
  guessRef.value?.getMore()
}
// 是否加载中标记
const isLoading = ref(false)
// 加载设置
onLoad(async () => {
  isLoading.value = true
  await Promise.all([getHomeBannerDate(), getHomeCategoryDate(), getgetHomeHotDate()])
  isLoading.value = false
})
// 下拉刷新状态
const isTriggered = ref(false)
// 自定义下拉刷新被触发
const onRefresherrefresh = async () => {
  console.log('被下拉')
  // 开启动画
  isTriggered.value = true
  // 重置猜你喜欢组件数据
  guessRef.value?.resetData() // 加载数据
  await Promise.all([
    getHomeBannerDate(),
    getHomeCategoryDate(),
    getgetHomeHotDate(),
    guessRef.value?.getMore(),
  ])
  // 关闭动画
  isTriggered.value = false
}
</script>
<template>
  <!-- 自定义导航栏 -->
  <CoustomNavbar />
  <!-- 使用这个来实现上面的不会滚动 -->
  <!-- <scroll-view scroll-y @scrolltolower="onScrolltolower"> -->
  <scroll-view
    refresher-enabled
    @refresherrefresh="onRefresherrefresh"
    @scrolltolower="onScrolltolower"
    :refresher-triggered="isTriggered"
    class="scroll-view"
    scroll-y
  >
    <PageSkeleton v-if="isLoading" />
    <template v-else>
      <XtxSwiper :list="bannerList" />
      <CategoryPanel :list="categoryList" />
      <!-- 热门推荐 -->
      <HotPanel :list="hotList" />
      <!-- 猜你喜欢,已经在pages.json中实现了自动导入 -->
      <XtxGuess ref="guessRef" />
    </template>
  </scroll-view>
</template>
<style lang="scss">
// 修改小程序的颜色 类似html5中为body指定颜色
page {
  background-color: #f7f7f7;
  height: 100%;
  display: flex;
  flex-direction: column;
}
.scroll-view {
  flex: 1;
}
</style>

Day 3

热门推荐

注意!! 删掉hot页面的时候不会减少

import { http } from '@/utils/http'
import type { PageParams } from '@/types/global'
type HotParams = PageParams & {
  /** Tab 项的 id,默认查询全部 Tab 项的第 1 页数据 */
  subType?: string
}
/**
 * 通用热门推荐类型
 * @param url 请求地址
 * @param data 请求参数
 */
export const getHotRecommendAPI = (url: string, data?: HotParams ) => {
  return http({
    method: 'GET',
    url,
    data,
  })
}

我看不懂上面这段带代码!

动态获取热门数据

热门推荐

前端类型复用思想

热门推荐页面渲染和tab交互

为什么有这么多不同的ref

  • 中间那个是组型

  • 为什么使用v-show 因为v-if会反复销毁创建 而v-show只是切换 滚动记录也是会独立

  • 没有什么值得说的 就是基础的项目渲染啥的 唯一特殊的是介绍了一个配置开发环境

通用项目技巧

开发页面环境

商品分类

编译模式

  • 这里也没有什么好说的 内容很重复 建议自己独立写一遍

商品详情

Day 4

小程序快捷登录

非空断言的正确认识

小程序页面跳转

小程序的页面跳转分为普通页面和tab页面

普通页面使用navigateTo tab页面使用switchTab

// 模拟手机号码快捷登录
const onGetphonenumberSimple = async () => {
  const res = await postLoginWxMinSimpleAPI('17338870680')
  const memberStore = useMemberStore()
  // pinia自带存储数据方法
  memberStore.setProfile(res.result)
  uni.showToast({ icon: 'none', title: '登录成功' })
  // 使用这段代码是因为 跳转tab页面会销毁掉之前的页面 所以会看不到提示
  setTimeout(() => {
    uni.switchTab({ url: '/pages/my/my ' })
  }, 500)
}

会员中心

猜你喜欢组件封装

  • 这里其实不止猜你喜欢可以封装 还有首页用到的轮播图也可以使用组件进行封装

轮播图组件封装

// 获取轮播图函数
export const useBannerList = () => {
  const bannerList = ref<BannerItem[]>([])
  const getBannerData = async () => {
    const res = await getHomeBannerAPI(2)
    bannerList.value = res.result
  }
  return { getBannerData, bannerList }
}
import { useBannerList } from '@/composables/index'
const { getBannerData, bannerList } = useBannerList()
//在index.vue中需要取个别名
import { useBannerList } from '@/composables/index'
const { getBannerData: getHomeBannerDate, bannerList } = useBannerList()
  • 用到轮播图的地方就能使用
注意 有时候不是你的代码写的有问题 这里也会有开头提到的后端请求问题

这里如果分包没有加载成功 请检查

  • 正确的是 pagesMember
  • settings
  • 博主眼睛不太好 在这里看了半天都没发现自己写的代码有问题

{
  // pages.json
  // 组件自动映入规则
  "easycom": {
    // 开始自动扫描
    "autoscan": true,
    // 正则方式匹配
    "custom": {
      // uni-ui 规则如下配置
      "^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue",
      // 以Xtx 开头的组件,在components文件中查找引入(需要重启服务器)
      "^Xtx(.*)": "@/components/Xtx$1.vue"
    }
  },
  "pages": [
    //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
    // src/pages.json
    {
      "path": "pages/index/index",
      "style": {
        "navigationStyle": "custom", // 隐藏默认导航
        "navigationBarTextStyle": "white",
        "navigationBarTitleText": "首页"
      }
    },
    {
      "path": "pages/my/my",
      "style": {
        "navigationBarTitleText": "我的"
      }
    },
    {
      "path": "pages/cart/cart",
      "style": {
        "navigationBarTitleText": "购物车"
      }
    },
    {
      "path": "pages/category/category",
      "style": {
        "navigationBarTitleText": "分类"
      }
    },
    {
      "path": "pages/login/login",
      "style": {
        "navigationStyle": "custom", // 隐藏默认导航
        "navigationBarTextStyle": "white",
        "navigationBarTitleText": "登录"
      }
    },
    {
      "path": "pages/hot/hot",
      "style": {
        "navigationBarTitleText": "热门推荐"
      }
    },
    {
      "path": "pages/goods/goods",
      "style": {
        "navigationBarTitleText": "商品详情"
      }
    }
  ],
  "globalStyle": {
    "navigationBarTextStyle": "black",
    "navigationBarTitleText": "",
    "navigationBarBackgroundColor": "#F8F8F8",
    "backgroundColor": "#F8F8F8"
  },
  // 设置 TabBar
  "tabBar": {
    "color": "#333",
    "selectedColor": "#27ba9b",
    "backgroundColor": "#fff",
    "borderStyle": "white",
    "list": [
      {
        "text": "首页",
        "pagePath": "pages/index/index",
        "iconPath": "static/tabs/home_default.png",
        "selectedIconPath": "static/tabs/home_selected.png"
      },
      {
        "text": "分类",
        "pagePath": "pages/category/category",
        "iconPath": "static/tabs/category_default.png",
        "selectedIconPath": "static/tabs/category_selected.png"
      },
      {
        "text": "购物车",
        "pagePath": "pages/cart/cart",
        "iconPath": "static/tabs/cart_default.png",
        "selectedIconPath": "static/tabs/cart_selected.png"
      },
      {
        "text": "我的",
        "pagePath": "pages/my/my",
        "iconPath": "static/tabs/user_default.png",
        "selectedIconPath": "static/tabs/user_selected.png"
      }
    ]
  },
  "subPackages": [
{
  "root": "pagesMember",
  "pages": [
    {
      "path": "settings/settings",
      "style": {
        "navigationBarTitleText": "设置"
      }
    }
  ]
}
  ]
}

个人信息页

个人信息展示

  • 这里面有各种各样的数据渲染 不过不是很难
  • 主要有判断类型、分割字符之类的

会员信息展示的琐屑代码

<script setup lang="ts">
import { getMemberProfileAPI } from '@/services/profile'
import type { ProfileDetail } from '@/types/member'
import { onLoad } from '@dcloudio/uni-app'
import { ref } from 'vue'
// 获取屏幕边界到安全区域距离
const { safeAreaInsets } = uni.getSystemInfoSync()
// 获取个人信息
const profile = ref<ProfileDetail>()
const getMemberProfileData = async () => {
  const res = await getMemberProfileAPI()
  profile.value = res.result
}
onLoad(() => {
  getMemberProfileData()
})
</script>
<template>
  <view class="viewport">
    <!-- 导航栏 -->
    <view class="navbar" :style="{ paddingTop: safeAreaInsets?.top + 'px' }">
      <navigator open-type="navigateBack" class="back icon-left" hover-class="none"></navigator>
      <view class="title">个人信息</view>
    </view>
    <!-- 头像 -->
    <view class="avatar">
      <view class="avatar-content">
        <image class="image" :src="profile?.avatar" mode="aspectFill" />
        <text class="text">点击修改头像</text>
      </view>
    </view>
    <!-- 表单 -->
    <view class="form">
      <!-- 表单内容 -->
      <view class="form-content">
        <view class="form-item">
          <text class="label">账号</text>
          <text class="account">{{ profile?.account }}</text>
        </view>
        <view class="form-item">
          <text class="label">昵称</text>
          <input class="input" type="text" placeholder="请填写昵称" :value="profile?.nickname" />
        </view>
        <view class="form-item">
          <text class="label">性别</text>
          <radio-group>
            <label class="radio">
              <radio value="男" color="#27ba9b" :checked="profile?.gender === '男'" />
            </label>
            <label class="radio">
              <radio value="女" color="#27ba9b" :checked="profile?.gender === '女'" />
            </label>
          </radio-group>
        </view>
        <view class="form-item">
          <text class="label">出生日期</text>
          <picker
            class="picker"
            mode="date"
            :value="profile?.birthday"
            start="1900-01-01"
            :end="new Date()"
          >
            <view v-if="profile?.birthday">{{ profile?.birthday }}</view>
            <view class="placeholder" v-else>请选择日期</view>
          </picker>
        </view>
        <view class="form-item">
          <text class="label">城市</text>
          <picker class="picker" :value="profile?.fullLocation?.split(' ')" mode="region">
            <view v-if="profile?.fullLocation">{{ profile.fullLocation }}</view>
            <view class="placeholder" v-else>请选择城市</view>
          </picker>
        </view>
        <view class="form-item">
          <text class="label">职业</text>
          <input class="input" type="text" placeholder="请填写职业" :value="profile?.profession" />
        </view>
      </view>
      <!-- 提交按钮 -->
      <button class="form-button">保 存</button>
    </view>
  </view>
</template>
<style lang="scss">
page {
  background-color: #f4f4f4;
}
.viewport {
  display: flex;
  flex-direction: column;
  height: 100%;
  background-image: url(https://pcapi-xiaotuxian-front-devtest.itheima.net/miniapp/images/order_bg.png);
  background-size: auto 420rpx;
  background-repeat: no-repeat;
}
// 导航栏
.navbar {
  position: relative;
  .title {
    height: 40px;
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 16px;
    font-weight: 500;
    color: #fff;
  }
  .back {
    position: absolute;
    height: 40px;
    width: 40px;
    left: 0;
    font-size: 20px;
    color: #fff;
    display: flex;
    justify-content: center;
    align-items: center;
  }
}
// 头像
.avatar {
  text-align: center;
  width: 100%;
  height: 260rpx;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  .image {
    width: 160rpx;
    height: 160rpx;
    border-radius: 50%;
    background-color: #eee;
  }
  .text {
    display: block;
    padding-top: 20rpx;
    line-height: 1;
    font-size: 26rpx;
    color: #fff;
  }
}
// 表单
.form {
  background-color: #f4f4f4;
  &-content {
    margin: 20rpx 20rpx 0;
    padding: 0 20rpx;
    border-radius: 10rpx;
    background-color: #fff;
  }
  &-item {
    display: flex;
    height: 96rpx;
    line-height: 46rpx;
    padding: 25rpx 10rpx;
    background-color: #fff;
    font-size: 28rpx;
    border-bottom: 1rpx solid #ddd;
    &:last-child {
      border: none;
    }
    .label {
      width: 180rpx;
      color: #333;
    }
    .account {
      color: #666;
    }
    .input {
      flex: 1;
      display: block;
      height: 46rpx;
    }
    .radio {
      margin-right: 20rpx;
    }
    .picker {
      flex: 1;
    }
    .placeholder {
      color: #808080;
    }
  }
  &-button {
    height: 80rpx;
    text-align: center;
    line-height: 80rpx;
    margin: 30rpx 20rpx;
    color: #fff;
    border-radius: 80rpx;
    font-size: 30rpx;
    background-color: #27ba9b;
  }
}
</style>

  • 教程使用的是chooseMedia,只能在小程序中使用,多端需要考虑使用chooseimage

渲染与修改

  • 这里需要对昵称数据进行即修改又使用
  • v-model会对数据进行先读取再绑定 但这时候不能为空 所以读不到

const onSubmit = async () => {
  console.log('123')
  const res = await putMemberProfileAPI({
    nickname: profile.value?.nickname,
  })
  uni.showToast({ icon: 'success', title: '保存成功' })
}
      <!-- 提交按钮 -->
      <button @tap="onSubmit" class="form-button">保 存</button>

跟新store信息

// 这里将gender设置的类型不是string 所以需要使用as 指定为gender
const onGenderChange: UniHelper.RadioGroupOnChange = (ev) => {
  profile.value.gender = ev.detail.value as Gender
}

  • 记得再submit中将参数传递给后端

会员修改城市

最终代码

<script setup lang="ts">
import { getMemberProfileAPI, putMemberProfileAPI } from '@/services/profile'
import { useMemberStore } from '@/stores'
import type { Gender, ProfileDetail } from '@/types/member'
import { onLoad } from '@dcloudio/uni-app'
import { ref } from 'vue'
// 获取屏幕边界到安全区域距离
const { safeAreaInsets } = uni.getSystemInfoSync()
// 获取个人信息 修改个人信息所需初始值
const profile = ref({} as ProfileDetail)
const getMemberProfileData = async () => {
  const res = await getMemberProfileAPI()
  profile.value = res.result
}
onLoad(() => {
  getMemberProfileData()
})
const memberStore = useMemberStore()
// 修改头像
const onAvatarChange = () => {
  // 调用拍照/选择图片
  uni.chooseMedia({
    // 文件个数
    count: 1,
    // 文件类型
    mediaType: ['image'],
    success: (res) => {
      // 本地路径
      const { tempFilePath } = res.tempFiles[0]
      // 文件上传
      uni.uploadFile({
        url: '/member/profile/avatar',
        name: 'file', // 后端数据字段名
        filePath: tempFilePath, // 新头像
        success: (res) => {
          // 判断状态码是否上传成功
          if (res.statusCode === 200) {
            // 提取头像
            const { avatar } = JSON.parse(res.data).result
            // 当前页面更新头像
            profile.value!.avatar = avatar
            // 更新 Store 头像
            memberStore.profile!.avatar = avatar
            uni.showToast({ icon: 'success', title: '更新成功' })
          } else {
            uni.showToast({ icon: 'error', title: '出现错误' })
          }
        },
      })
    },
  })
}
// 这里将gender设置的类型不是string 所以需要使用as 指定为gender
const onGenderChange: UniHelper.RadioGroupOnChange = (ev) => {
  profile.value.gender = ev.detail.value as Gender
}
// 修改生日
const onBirthdayChange: UniHelper.DatePickerOnChange = (ev) => {
  profile.value.birthday = ev.detail.value
}
// 修改城市
let fullLocationCode: [string, string, string] = ['', '', '']
const onFullLocationChange: UniHelper.RegionPickerOnChange = (ev) => {
  // 修改前端界面
  profile.value.fullLocation = ev.detail.value.join(' ')
  // 提交后端更新
  fullLocationCode = ev.detail.code!
}
const onSubmit = async () => {
  const { nickname, gender, birthday, profession } = profile.value
  const res = await putMemberProfileAPI({
    nickname,
    gender,
    birthday,
    profession,
    provinceCode: fullLocationCode[0],
    cityCode: fullLocationCode[1],
    countyCode: fullLocationCode[2],
  })
  // 更新store昵称
  memberStore.profile!.nickname = res.result.nickname
  uni.showToast({ icon: 'success', title: '保存成功' })
  setTimeout(() => {
    uni.navigateBack()
  }, 400)
}
</script>
<template>
  <view class="viewport">
    <!-- 导航栏 -->
    <view class="navbar" :style="{ paddingTop: safeAreaInsets?.top + 'px' }">
      <navigator open-type="navigateBack" class="back icon-left" hover-class="none"></navigator>
      <view class="title">个人信息</view>
    </view>
    <!-- 头像 -->
    <view class="avatar">
      <view @tap="onAvatarChange" class="avatar-content">
        <image class="image" :src="profile?.avatar" mode="aspectFill" />
        <text class="text">点击修改头像</text>
      </view>
    </view>
    <!-- 表单 -->
    <view class="form">
      <!-- 表单内容 -->
      <view class="form-content">
        <view class="form-item">
          <text class="label">账号</text>
          <text class="account">{{ profile?.account }}</text>
        </view>
        <view class="form-item">
          <text class="label">昵称</text>
          <input class="input" type="text" placeholder="请填写昵称" v-model="profile!.nickname" />
        </view>
        <view class="form-item">
          <text class="label">性别</text>
          <radio-group @change="onGenderChange">
            <label class="radio">
              <radio value="男" color="#27ba9b" :checked="profile?.gender === '男'" />
            </label>
            <label class="radio">
              <radio value="女" color="#27ba9b" :checked="profile?.gender === '女'" />
            </label>
          </radio-group>
        </view>
        <view class="form-item">
          <text class="label">生日</text>
          <picker
            class="picker"
            mode="date"
            start="1900-01-01"
            :end="new Date()"
            :value="profile.birthday"
            @change="onBirthdayChange"
          >
            <view v-if="profile.birthday">{{ profile.birthday }}</view>
            <view class="placeholder" v-else>请选择日期</view>
          </picker>
        </view>
        <view class="form-item">
          <text class="label">城市</text>
          <picker
            class="picker"
            mode="region"
            :value="profile.fullLocation?.split(' ')"
            @change="onFullLocationChange"
          >
            <view v-if="profile.fullLocation">{{ profile.fullLocation }}</view>
            <view class="placeholder" v-else>请选择城市</view>
          </picker>
        </view>
        <view class="form-item">
          <text class="label">职业</text>
          <input class="input" type="text" placeholder="请填写职业" :value="profile?.profession" />
        </view>
      </view>
      <!-- 提交按钮 -->
      <button @tap="onSubmit" class="form-button">保 存</button>
    </view>
  </view>
</template>
<style lang="scss">
page {
  background-color: #f4f4f4;
}
.viewport {
  display: flex;
  flex-direction: column;
  height: 100%;
  background-image: url(https://pcapi-xiaotuxian-front-devtest.itheima.net/miniapp/images/order_bg.png);
  background-size: auto 420rpx;
  background-repeat: no-repeat;
}
// 导航栏
.navbar {
  position: relative;
  .title {
    height: 40px;
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 16px;
    font-weight: 500;
    color: #fff;
  }
  .back {
    position: absolute;
    height: 40px;
    width: 40px;
    left: 0;
    font-size: 20px;
    color: #fff;
    display: flex;
    justify-content: center;
    align-items: center;
  }
}
// 头像
.avatar {
  text-align: center;
  width: 100%;
  height: 260rpx;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  .image {
    width: 160rpx;
    height: 160rpx;
    border-radius: 50%;
    background-color: #eee;
  }
  .text {
    display: block;
    padding-top: 20rpx;
    line-height: 1;
    font-size: 26rpx;
    color: #fff;
  }
}
// 表单
.form {
  background-color: #f4f4f4;
  &-content {
    margin: 20rpx 20rpx 0;
    padding: 0 20rpx;
    border-radius: 10rpx;
    background-color: #fff;
  }
  &-item {
    display: flex;
    height: 96rpx;
    line-height: 46rpx;
    padding: 25rpx 10rpx;
    background-color: #fff;
    font-size: 28rpx;
    border-bottom: 1rpx solid #ddd;
    &:last-child {
      border: none;
    }
    .label {
      width: 180rpx;
      color: #333;
    }
    .account {
      color: #666;
    }
    .input {
      flex: 1;
      display: block;
      height: 46rpx;
    }
    .radio {
      margin-right: 20rpx;
    }
    .picker {
      flex: 1;
    }
    .placeholder {
      color: #808080;
    }
  }
  &-button {
    height: 80rpx;
    text-align: center;
    line-height: 80rpx;
    margin: 30rpx 20rpx;
    color: #fff;
    border-radius: 80rpx;
    font-size: 30rpx;
    background-color: #27ba9b;
  }
}
</style>

TS开发项目于JS开发项目的不同

  • 不同之处就是指定类型
  • 在编写发送请求的时候,js项目只要http{}然后开始写相关接口数据而Ts项目还要给http<>{}指定一个类型,用来判断请求返回值是否符合编写时的要求
  • TS的类型有别于java类型,简单的number是对应int、long。但自定义的数据类型,如果要用java来理解的话,我认为TS类型像数据结构,像枚举。 TS定义的类型就是数据的组织形式,这个组织形式是根据返回的数据不同而不同
fy-content: center;
align-items: center;
font-size: 16px;
font-weight: 500;
color: #fff;
}
.back {
position: absolute;
height: 40px;
width: 40px;
left: 0;
font-size: 20px;
color: #fff;
display: flex;
justify-content: center;
align-items: center;
}
}
// 头像
.avatar {
text-align: center;
width: 100%;
height: 260rpx;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.image {
width: 160rpx;
height: 160rpx;
border-radius: 50%;
background-color: #eee;
}
.text {
display: block;
padding-top: 20rpx;
line-height: 1;
font-size: 26rpx;
color: #fff;
}
}
// 表单
.form {
background-color: #f4f4f4;
&-content {
margin: 20rpx 20rpx 0;
padding: 0 20rpx;
border-radius: 10rpx;
background-color: #fff;
}
&-item {
display: flex;
height: 96rpx;
line-height: 46rpx;
padding: 25rpx 10rpx;
background-color: #fff;
font-size: 28rpx;
border-bottom: 1rpx solid #ddd;
&:last-child {
  border: none;
}
.label {
  width: 180rpx;
  color: #333;
}
.account {
  color: #666;
}
.input {
  flex: 1;
  display: block;
  height: 46rpx;
}
.radio {
  margin-right: 20rpx;
}
.picker {
  flex: 1;
}
.placeholder {
  color: #808080;
}
}
&-button {
height: 80rpx;
text-align: center;
line-height: 80rpx;
margin: 30rpx 20rpx;
color: #fff;
border-radius: 80rpx;
font-size: 30rpx;
background-color: #27ba9b;
}
}
# TS开发项目于JS开发项目的不同
+ 不同之处就是指定类型 
+ 在编写发送请求的时候,js项目只要http{}然后开始写相关接口数据而Ts项目还要给http<>{}指定一个类型,用来判断请求返回值是否符合编写时的要求
+ TS的类型有别于java类型,简单的number是对应int、long。但自定义的数据类型,如果要用java来理解的话,我认为TS类型像数据结构,像枚举。 TS定义的类型就是数据的组织形式,这个组织形式是根据返回的数据不同而不同


目录
相关文章
|
5月前
|
前端开发 Java 数据安全/隐私保护
计算机Java项目|基于Andriod技术“厕ce”APP
计算机Java项目|基于Andriod技术“厕ce”APP
|
1月前
|
XML Java 数据库
安卓项目:app注册/登录界面设计
本文介绍了如何设计一个Android应用的注册/登录界面,包括布局文件的创建、登录和注册逻辑的实现,以及运行效果的展示。
151 0
安卓项目:app注册/登录界面设计
|
3月前
|
Java 应用服务中间件 Windows
【应用服务 App Service】App Service 中部署Java项目,查看Tomcat配置及上传自定义版本
【应用服务 App Service】App Service 中部署Java项目,查看Tomcat配置及上传自定义版本
|
1月前
|
移动开发 小程序 数据可视化
基于npm CLI脚手架的uniapp项目创建、运行与打包全攻略(微信小程序、H5、APP全覆盖)
基于npm CLI脚手架的uniapp项目创建、运行与打包全攻略(微信小程序、H5、APP全覆盖)
241 3
|
1月前
|
缓存 开发框架 移动开发
uni-app:下载使用uni&创建项目&和小程序链接&数据缓存&小程序打包 (一)
uni-app 是一个跨平台的开发框架,它允许开发者使用 Vue.js 来构建应用程序,并能够同时发布到多个平台,如微信小程序、支付宝小程序、H5、App(通过DCloud的打包服务)等。uni-app 的目标是通过统一的代码库,简化多平台开发过程,提高开发效率。 在这一部分中,我们将逐步介绍如何下载和使用uni-app、创建一个新的项目、如何将项目链接到小程序,以及实现数据缓存的基本方法。
|
3月前
|
小程序 前端开发 Java
SpringBoot+uniapp+uview打造H5+小程序+APP入门学习的聊天小项目
JavaDog Chat v1.0.0 是一款基于 SpringBoot、MybatisPlus 和 uniapp 的简易聊天软件,兼容 H5、小程序和 APP,提供丰富的注释和简洁代码,适合初学者。主要功能包括登录注册、消息发送、好友管理及群组交流。
108 0
SpringBoot+uniapp+uview打造H5+小程序+APP入门学习的聊天小项目
|
3月前
|
开发框架 .NET Docker
【Azure 应用服务】App Service .NET Core项目在Program.cs中自定义添加的logger.LogInformation,部署到App Service上后日志不显示Log Stream中的问题
【Azure 应用服务】App Service .NET Core项目在Program.cs中自定义添加的logger.LogInformation,部署到App Service上后日志不显示Log Stream中的问题
|
3月前
|
JavaScript Windows
【Azure 应用服务】用App Service部署运行 Vue.js 编写的项目,应该怎么部署运行呢?
【Azure 应用服务】用App Service部署运行 Vue.js 编写的项目,应该怎么部署运行呢?
|
3月前
|
Java 开发工具 git
【Azure 应用服务】本地Git部署Java项目到App Server,访问无效的原因
【Azure 应用服务】本地Git部署Java项目到App Server,访问无效的原因
|
3月前
|
Linux Python
【Azure 应用服务】Azure App Service For Linux 上实现 Python Flask Web Socket 项目 Http/Https
【Azure 应用服务】Azure App Service For Linux 上实现 Python Flask Web Socket 项目 Http/Https

热门文章

最新文章

下一篇
无影云桌面