【前端Vue】社交信息头条项目完整笔记第2篇:二、登录注册,准备【附代码文档】

社交媒体-信息头条项目完整开发笔记完整教程(附代码资料)主要内容讲述:一、项目初始化使用 Vue CLI 创建项目,加入 Git 版本管理,调整初始目录结构,导入图标素材,引入 Vant 组件库,移动端 REM 适配,关于 , 配置文件,封装请求模块。十、用户关注 & 粉丝。十一、我的收藏/历史。十二、编辑用户资料创建组件并配置路由,页面布局,展示用户信息,修改昵称,修改性别,修改生日,修改头像。二、登录注册准备,实现基本登录功能,登录状态提示,表单验证,验证码处理,处理用户 Token,优化封装本地存储操作模块,关于 Token 过期问题。三、个人中心TabBar 处理,页面布局,处理已登录和未登录的页面展示,用户退出,展示登录用户信息,优化设置 Token。四、首页—文章列表页面布局,频道列表,文章列表,文章列表项。五、首页—频道编辑处理页面弹出层,创建频道编辑组件,页面布局,展示我的频道,展示推荐频道列表,添加频道,编辑频道,频道数据持久化,正确的获取首页频道列表数据。六、文章搜索创建组件并配置路由,页面布局,处理页面显示状态,搜索联想建议,搜索结果,搜索历史记录。七、文章详情创建组件并配置路由,页面布局,关于后端返回数据中的大数字问题,展示文章详情,处理内容加载状态,关于文章正文的样式,图片点击预览,关注用户,文章收藏,文章点赞。八、文章评论展示文章评论列表,评论点赞,发布文章评论,评论回复。九、用户页面创建组件并配置路由,页面布局,展示用户信息,用户关注,展示用户文章列表。

全套笔记资料代码移步: 前往gitee仓库查看

感兴趣的小伙伴可以自取哦,欢迎大家点赞转发~


全套教程部分目录:


部分文件图片:

二、登录注册

目标

  • 能实现登录页面的布局
  • 能实现基本登录功能
  • 能掌握 Vant 中 Toast 提示组件的使用
  • 能理解 API 请求模块的封装
  • 能理解发送验证码的实现思路
  • 能理解 Vant Form 实现表单验证的使用
image-20200228161041266

准备

创建组件并配置路由

1、创建 src/views/login/index.vue 并写入以下内容

<template>
  <div class="login-container">登录页面</div>
</template>

<script>
export default {
  name: 'LoginPage',
  components: {},
  props: {},
  data () {
    return {}
  },
  computed: {},
  watch: {},
  created () {},
  mounted () {},
  methods: {}
}
</script>

<style scoped lang="less"></style>

2、然后在 src/router/index.js 中配置登录页的路由表

{
  path: '/login',
  name: 'login',
  component: () => import('@/views/login')
}

最后,访问 /login 查看是否能访问到登录页面。

image-20200229115109026

布局结构

这里主要使用到三个 Vant 组件:

  • [NavBar 导航栏](
  • [Form 表单](
    • [Field 输入框](
    • [Button 按钮](

一个经验:使用组件库中的现有组件快速布局,再慢慢调整细节,效率更高(刚开始可能会感觉有点麻烦,越用越熟,慢慢的就有了自己的思想)。

布局样式

写样式的原则:将公共样式写到全局(src/styles/index.less),将局部样式写到组件内部。

1、src/styles/index.less

body {
  background-color: #f5f7f9;
}

.page-nav-bar {
  background-color: #3296fa;
  .van-nav-bar__title {
    color: #fff;
  }
}

2、src/views/login/index.vue

<template>
  <div class="login-container">
    <!-- 导航栏 -->
    <van-nav-bar class="page-nav-bar" title="登录" />
    <!-- /导航栏 -->

    <!-- 登录表单 -->
    <van-form @submit="onSubmit">
      <van-field
        name="用户名"
        placeholder="请输入手机号"
      >
        <i slot="left-icon" class="toutiao toutiao-shouji"></i>
      </van-field>
      <van-field
        type="password"
        name="验证码"
        placeholder="请输入验证码"
      >
        <i slot="left-icon" class="toutiao toutiao-yanzhengma"></i>
        <template #button>
          <van-button class="send-sms-btn" round size="small" type="default">发送验证码</van-button>
        </template>
      </van-field>
      <div class="login-btn-wrap">
        <van-button class="login-btn" block type="info" native-type="submit">
          登录
        </van-button>
      </div>
    </van-form>
    <!-- /登录表单 -->
  </div>
</template>

<script>
export default {
  name: 'LoginIndex',
  components: {},
  props: {},
  data () {
    return {
    }
  },
  computed: {},
  watch: {},
  created () {},
  mounted () {},
  methods: {
    onSubmit (values) {
      console.log('submit', values)
    }
  }
}
</script>

<style scoped lang="less">
.login-container {
  .toutiao {
    font-size: 37px;
  }
  .send-sms-btn {
    width: 152px;
    height: 46px;
    line-height: 46px;
    background-color: #ededed;
    font-size: 22px;
    color: #666;
  }
  .login-btn-wrap {
    padding: 53px 33px;
    .login-btn {
      background-color: #6db4fb;
      border: none;
    }
  }
}
</style>

实现基本登录功能

思路:

  • 注册点击登录的事件
  • 获取表单数据(根据接口要求使用 v-model 绑定)
  • 表单验证
  • 发请求提交
  • 根据请求结果做下一步处理

一、根据接口要求绑定获取表单数据

1、在登录页面组件的实例选项 data 中添加 user 数据字段

...
data () {
  return {
    user: {
      mobile: '',
      code: ''
    }
  }
}

2、在表单中使用 v-model 绑定对应数据

<!-- van-cell-group 仅仅是提供了一个上下外边框,能看到包裹的区域 -->
<van-cell-group>
  <van-field
    v-model="user.mobile"
    required
    clearable
    label="手机号"
    placeholder="请输入手机号"
  />

  <van-field
    v-model="user.code"
    type="number"
    label="验证码"
    placeholder="请输入验证码"
    required
  />
</van-cell-group>

最后测试。

一个小技巧:使用 VueDevtools 调试工具查看是否绑定成功。

二、请求登录

1、创建 src/api/user.js 封装请求方法

/**
 * 用户相关的请求模块
 */
import request from "@/utils/request"

/**
 * 用户登录
 */
export const login = data => {
  return request({
    method: 'POST',
    url: '/app/v1_0/authorizations',
    data
  })
}

2、给登录按钮注册点击事件

async onLogin () {
  try {
    const res = await login(this.user)
    console.log('登录成功', res)
  } catch (err) {
    if (err.response.status === 400) {
     	console.log('登录失败', err)
    }
  }
}

最后测试。

登录状态提示

Vant 中内置了[Toast 轻提示](

// 简单文字提示
Toast("提示内容");

// loading 转圈圈提示
Toast.loading({
  duration: 0, // 持续展示 toast
  message: "加载中...",
  forbidClick: true // 是否禁止背景点击
});

// 成功提示
Ttoast.success("成功文案");

// 失败提示
Toast.fail("失败文案");

提示:在组件中可以直接通过 this.$toast 调用。

另外需要注意的是:Toast 默认采用单例模式,即同一时间只会存在一个 Toast,如果需要在同一时间弹出多个 Toast,可以参考下面的示例

Toast.allowMultiple();

const toast1 = Toast('第一个 Toast');
const toast2 = Toast.success('第二个 Toast');

toast1.clear();
toast2.clear();

下面是为我们的登录功能增加 toast 交互提示。

async onLogin () {
  // 开始转圈圈
  this.$toast.loading({
    duration: 0, // 持续时间,0表示持续展示不停止
    forbidClick: true, // 是否禁止背景点击
    message: '登录中...' // 提示消息
  })

  try {
    const res = await request({
      method: 'POST',
      url: '/app/v1_0/authorizations',
      data: this.user
    })
    console.log('登录成功', res)
    // 提示 success 或者 fail 的时候,会先把其它的 toast 先清除
    this.$toast.success('登录成功')
  } catch (err) {
    console.log('登录失败', err)
    this.$toast.fail('登录失败,手机号或验证码错误')
  }
}

假如请求非常快的话就看不到 loading 效果了,这里可以手动将调试工具中的网络设置为慢速网络。

测试结束,再把网络设置恢复为 Online 正常网络。

表单验证

参考文档:[Form 表单验证](

<template>
  <div class="login-container">
    <!-- 导航栏 -->
    <van-nav-bar class="page-nav-bar" title="登录" />
    <!-- /导航栏 -->

    <!-- 登录表单 -->
    <!--
      表单验证:
        1、给 van-field 组件配置 rules 验证规则
          参考文档:
        2、当表单提交的时候会自动触发表单验证
           如果验证通过,会触发 submit 事件
           如果验证失败,不会触发 submit
     -->
    <van-form @submit="onSubmit">
      <van-field
        v-model="user.mobile"
        name="手机号"
        placeholder="请输入手机号"
        :rules="userFormRules.mobile"
        type="number"
        maxlength="11"
      >
        <i slot="left-icon" class="toutiao toutiao-shouji"></i>
      </van-field>
      <van-field
        v-model="user.code"
        name="验证码"
        placeholder="请输入验证码"
        :rules="userFormRules.code"
        type="number"
        maxlength="6"
      >
        <i slot="left-icon" class="toutiao toutiao-yanzhengma"></i>
        <template #button>
          <van-button class="send-sms-btn" round size="small" type="default">发送验证码</van-button>
        </template>
      </van-field>
      <div class="login-btn-wrap">
        <van-button class="login-btn" block type="info" native-type="submit">
          登录
        </van-button>
      </div>
    </van-form>
    <!-- /登录表单 -->
  </div>
</template>

<script>
import { login } from '@/api/user'

export default {
  name: 'LoginIndex',
  components: {},
  props: {},
  data () {
    return {
      user: {
        mobile: '', // 手机号
        code: '' // 验证码
      },
      userFormRules: {
        mobile: [{
          required: true,
          message: '手机号不能为空'
        }, {
          pattern: /^1[3|5|7|8]\d{9}$/,
          message: '手机号格式错误'
        }],
        code: [{
          required: true,
          message: '验证码不能为空'
        }, {
          pattern: /^\d{6}$/,
          message: '验证码格式错误'
        }]
      }
    }
  },
  computed: {},
  watch: {},
  created () {},
  mounted () {},
  methods: {
    async onSubmit () {
      // 1. 获取表单数据
      const user = this.user

      // TODO: 2. 表单验证

      // 3. 提交表单请求登录
      this.$toast.loading({
        message: '登录中...',
        forbidClick: true, // 禁用背景点击
        duration: 0 // 持续时间,默认 2000,0 表示持续展示不关闭
      })

      try {
        const res = await login(user)
        console.log('登录成功', res)
        this.$toast.success('登录成功')
      } catch (err) {
        if (err.response.status === 400) {
          this.$toast.fail('手机号或验证码错误')
        } else {
          this.$toast.fail('登录失败,请稍后重试')
        }
      }

      // 4. 根据请求响应结果处理后续操作
    }
  }
}
</script>

<style scoped lang="less">
.login-container {
  .toutiao {
    font-size: 37px;
  }

  .send-sms-btn {
    width: 152px;
    height: 46px;
    line-height: 46px;
    background-color: #ededed;
    font-size: 22px;
    color: #666;
  }

  .login-btn-wrap {
    padding: 53px 33px;
    .login-btn {
      background-color: #6db4fb;
      border: none;
    }
  }
}
</style>

验证码处理

验证手机号

async onSendSms () {
  console.log('onSendSms')
  // 1. 校验手机号
  try {
    await this.$refs.loginForm.validate('mobile')
  } catch (err) {
    return console.log('验证失败', err)
  }

  // 2. 验证通过,显示倒计时
  // 3. 请求发送验证码
}

使用倒计时组件

1、在 data 中添加数据用来控制倒计时的显示和隐藏

data () {
  return {
    ...
    isCountDownShow: false
  }
}

2、使用倒计时组件

<van-field
  v-model="user.code"
  placeholder="请输入验证码"
>
  <i class="icon icon-mima" slot="left-icon"></i>
  <van-count-down
    v-if="isCountDownShow"
    slot="button"
    :time="1000 * 5"
    format="ss s"
    @finish="isCountDownShow = false"
  />
  <van-button
    v-else
    slot="button"
    size="small"
    type="primary"
    round
    @click="onSendSmsCode"
  >发送验证码</van-button>
</van-field>

发送验证码

1、在 api/user.js 中添加封装数据接口

export const getSmsCode = mobile => {
  return request({
    method: 'GET',
    url: `/app/v1_0/sms/codes/${mobile}`
  })
}

2、给发送验证码按钮注册点击事件

3、发送处理

async onSendSms () {
  // 1. 校验手机号
  try {
    await this.$refs.loginForm.validate('mobile')
  } catch (err) {
    return console.log('验证失败', err)
  }

  // 2. 验证通过,显示倒计时
  this.isCountDownShow = true

  // 3. 请求发送验证码
  try {
    await sendSms(this.user.mobile)
    this.$toast('发送成功')
  } catch (err) {
    // 发送失败,关闭倒计时
    this.isCountDownShow = false
    if (err.response.status === 429) {
      this.$toast('发送太频繁了,请稍后重试')
    } else {
      this.$toast('发送失败,请稍后重试')
    }
  }
}

处理用户 Token

image-20200329121650635

Token 是用户登录成功之后服务端返回的一个身份令牌,在项目中的多个业务中需要使用到:

  • 访问需要授权的 API 接口
  • 校验页面的访问权限

但是我们只有在第一次用户登录成功之后才能拿到 Token。

所以为了能在其它模块中获取到 Token 数据,我们需要把它存储到一个公共的位置,方便随时取用。

往哪儿存?

  • 本地存储
    • 获取麻烦
    • 数据不是响应式
  • Vuex 容器(推荐)
    • 获取方便
    • 响应式的

使用容器存储 Token 的思路:

image-20200109192157006

  • 登录成功,将 Token 存储到 Vuex 容器中
    • 获取方便
    • 响应式
  • 为了持久化,还需要把 Token 放到本地存储
    • 持久化

下面是具体实现。

1、在 src/store/index.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    // 用户的登录状态信息
    user: JSON.parse(window.localStorage.getItem('TOUTIAO_USER'))
    // user: null
  },
  mutations: {
    setUser (state, user) {
      state.user = user
      window.localStorage.setItem('TOUTIAO_USER', JSON.stringify(user))
    }
  },
  actions: {
  },
  modules: {
  }
})

2、登录成功以后将后端返回的 token 相关数据存储到容器中

async onLogin () {
  // const loginToast = this.$toast.loading({
  this.$toast.loading({
    duration: 0, // 持续时间,0表示持续展示不停止
    forbidClick: true, // 是否禁止背景点击
    message: '登录中...' // 提示消息
  })

  try {
    const res = await login(this.user)

    // res.data.data => { token: 'xxx', refresh_token: 'xxx' }
+    this.$store.commit('setUser', res.data.data)

    // 提示 success 或者 fail 的时候,会先把其它的 toast 先清除
    this.$toast.success('登录成功')
  } catch (err) {
    console.log('登录失败', err)
    this.$toast.fail('登录失败,手机号或验证码错误')
  }

  // 停止 loading,它会把当前页面中所有的 toast 都给清除
  // loginToast.clear()
}

优化封装本地存储操作模块

创建 src/utils/storage.js 模块。

export const getItem = name => {
  const data = window.localStorage.getItem(name)
  try {
    return JSON.parse(data)
  } catch (err) {
    return data
  }
}

export const setItem = (name, value) => {
  if (typeof value === 'object') {
    value = JSON.stringify(value)
  }
  window.localStorage.setItem(name, value)
}

export const removeItem = name => {
  window.localStorage.removeItem(name)
}

关于 Token 过期问题

登录成功之后后端会返回两个 Token:

  • token:访问令牌,有效期2小时
  • refresh_token:刷新令牌,有效期14天,用于访问令牌过期之后重新获取新的访问令牌

我们的项目接口中设定的 Token 有效期是 2 小时,超过有效期服务端会返回 401 表示 Token 无效或过期了。

为什么过期时间这么短?

  • 为了安全,例如 Token 被别人盗用

过期了怎么办?

  • 让用户重新登录,用户体验太差了
  • 使用 refresh_token 解决 token 过期

如何使用 refresh_token 解决 token 过期?

到课程的后面我们开发的业务功能丰富起来之后,再给大家讲解 Token 过期处理。

大家需要注意的是在学习测试的时候如果收到 401 响应码,请重新登录再测试

img

概述:服务器生成token的过程中,会有两个时间,一个是token失效时间,一个是token刷新时间,刷新时间肯定比失效时间长,当用户的 token 过期时,你可以拿着过期的token去换取新的token,来保持用户的登陆状态,当然你这个过期token的过期时间必须在刷新时间之内,如果超出了刷新时间,那么返回的依旧是 401。

处理流程:

  1. 在axios的拦截器中加入token刷新逻辑
  2. 当用户token过期时,去向服务器请求新的 token
  3. 把旧的token替换为新的token
  4. 然后继续用户当前的请求

在请求的响应拦截器中统一处理 token 过期:

/**
 * 封装 axios 请求模块
 */
import axios from "axios";
import jsonBig from "json-bigint";
import store from "@/store";
import router from "@/router";

// axios.create 方法:复制一个 axios
const request = axios.create({
  baseURL: " // 基础路径
});

/**
 * 配置处理后端返回数据中超出 js 安全整数范围问题
 */
request.defaults.transformResponse = [
  function(data) {
    try {
      return jsonBig.parse(data);
    } catch (err) {
      return {};
    }
  }
];

// 请求拦截器
request.interceptors.request.use(
  function(config) {
    const user = store.state.user;
    if (user) {
      config.headers.Authorization = `Bearer ${user.token}`;
    }
    // Do something before request is sent
    return config;
  },
  function(error) {
    // Do something with request error
    return Promise.reject(error);
  }
);

// 响应拦截器
request.interceptors.response.use(
  // 响应成功进入第1个函数
  // 该函数的参数是响应对象
  function(response) {
    // Any status code that lie within the range of 2xx cause this function to trigger
    // Do something with response data
    return response;
  },
  // 响应失败进入第2个函数,该函数的参数是错误对象
  async function(error) {
    // Any status codes that falls outside the range of 2xx cause this function to trigger
    // Do something with response error
    // 如果响应码是 401 ,则请求获取新的 token

    // 响应拦截器中的 error 就是那个响应的错误对象
    console.dir(error);
    if (error.response && error.response.status === 401) {
      // 校验是否有 refresh_token
      const user = store.state.user;

      if (!user || !user.refresh_token) {
        router.push("/login");

        // 代码不要往后执行了
        return;
      }

      // 如果有refresh_token,则请求获取新的 token
      try {
        const res = await axios({
          method: "PUT",
          url: "
          headers: {
            Authorization: `Bearer ${user.refresh_token}`
          }
        });

        // 如果获取成功,则把新的 token 更新到容器中
        console.log("刷新 token  成功", res);
        store.commit("setUser", {
          token: res.data.data.token, // 最新获取的可用 token
          refresh_token: user.refresh_token // 还是原来的 refresh_token
        });

        // 把之前失败的用户请求继续发出去
        // config 是一个对象,其中包含本次失败请求相关的那些配置信息,例如 url、method 都有
        // return 把 request 的请求结果继续返回给发请求的具体位置
        return request(error.config);
      } catch (err) {
        // 如果获取失败,直接跳转 登录页
        console.log("请求刷线 token 失败", err);
        router.push("/login");
      }
    }

    return Promise.reject(error);
  }
);

export default request;

未完待续, 同学们请等待下一期

全套笔记资料代码移步: 前往gitee仓库查看

感兴趣的小伙伴可以自取哦,欢迎大家点赞转发~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/496967.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

快速上手Spring Cloud 十四:璀璨物联网之路

快速上手Spring Cloud 一&#xff1a;Spring Cloud 简介 快速上手Spring Cloud 二&#xff1a;核心组件解析 快速上手Spring Cloud 三&#xff1a;API网关深入探索与实战应用 快速上手Spring Cloud 四&#xff1a;微服务治理与安全 快速上手Spring Cloud 五&#xff1a;Spring …

Java项目:78 springboot学生宿舍管理系统的设计与开发

作者主页&#xff1a;舒克日记 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 系统的角色&#xff1a;管理员、宿管、学生 管理员管理宿管员&#xff0c;管理学生&#xff0c;修改密码&#xff0c;维护个人信息。 宿管员管理公寓…

iOS - Runtime-API

文章目录 iOS - Runtime-API1. Runtime应用1.1 字典转模型1.2 替换方法实现1.3 利用关联对象给分类添加属性1.4 利用消息转发机制&#xff0c;解决方法找不到的异常问题 2. Runtime-API2.1 Runtime API01 – 类2.1.1 动态创建一个类&#xff08;参数&#xff1a;父类&#xff0…

轻松赚钱,精彩生活:上班族副业赚钱新攻略大揭秘!

薪水总是捉襟见肘&#xff0c;每月账单总让人倍感压力。你是否曾在静谧的夜晚&#xff0c;躺在床上&#xff0c;思索如何为家庭多赚一分钱&#xff1f;其实&#xff0c;你并不孤单。在这个充满机遇与挑战的时代&#xff0c;越来越多的人开始寻找副业&#xff0c;以期望让生活更…

Appium设备交互API

设备交互API指的是操作设备系统中的一些固有功能&#xff0c;而非被测程序的功能&#xff0c;例如模拟来电&#xff0c;模拟发送短信&#xff0c;设置网络&#xff0c;切换横竖屏&#xff0c;APP操作&#xff0c;打开通知栏&#xff0c;录屏等。 模拟来电 make_gsm_call(phon…

八数码问题

八数码难题 题目描述 在 3 3 3\times 3 33 的棋盘上&#xff0c;摆有八个棋子&#xff0c;每个棋子上标有 1 1 1 至 8 8 8 的某一数字。棋盘中留有一个空格&#xff0c;空格用 0 0 0 来表示。空格周围的棋子可以移到空格中。要求解的问题是&#xff1a;给出一种初始布局…

Java项目:79 springboot海滨体育馆管理系统的设计与实现

作者主页&#xff1a;源码空间codegym 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 体育馆管理系统主要实现了管理员功能模块和学生功能模块两大部分 管理员功能模块&#xff1a; 管理员登录后可对系统进行全面管理操作&#…

内网穿透_ICMP_icmpsh

目录 一、ICMP协议详解 二、ICMP隧道 (一) 为什么会使用ICMP (二) 实验环境 (三) 操作流程 1. 下载icmpsh 2. 下载并安装依赖 3. 关闭本地icmp响应 4. 攻击机启动服务端开始监听 5. 靶机启动工具客户端 6. 攻击机接受到靶机传来的数据 三、郑重声明 一、ICMP协议详…

LeetCode_1.两数之和

一、题目描述 二、方法 1.方法1&#xff08;暴力枚举法&#xff09; 利用两个for循环&#xff0c;对数组进行逐一的遍历&#xff0c;直到找到两个数的和为目标值时返回这两个数的下标。以下为c实现的完整代码。 # include<iostream> using namespace std; #include<…

C语言分支循环语句详解

分支和循环语句是什么 在我们写程序的时候&#xff0c;总会遇到想一直循环执行某种语句的时候&#xff0c;这时候我们就要使用一种语句叫循环语句&#xff0c;或者带一些判断条件的语句&#xff0c;在C语言中提供了像这些的循环语句和分支语句 if else 语句 这是一种判断语句…

AcWing 800. 数组元素的目标和(哈希)

原题链接 哈希思路: 我们可以在输入 时把每个数存进哈希表里&#xff0c;对于每个输入的 b[i]看看 x−b[i]是否出现与哈希表即可。 图解 #include <iostream> #include <algorithm> #include <unordered_map> using namespace std;const int N 111111;in…

使用 Yoda 和 ClickHouse 进行实时欺诈检测

背景 Instacart 是北美领先的在线杂货公司,拥有数百万活跃的客户和购物者。在其平台上打击欺诈和滥用行为不仅对于维护一个值得信赖和安全的环境至关重要,也对保持Instacart的财务健康至关重要。在这篇文章中,将介绍了一个欺诈平台——Yoda,解释了为什么我们选择ClickHous…

Game Maker 更新|在 The Sandbox 使用烹饪模拟器!

我们很高兴向你介绍 Game Maker 的最新更新&#xff1a;烹饪模拟器模板&#xff01;让自己沉浸在令人兴奋的新游戏类型中&#xff0c;同时学习有趣的新机制。剖析和探索模板&#xff0c;考验你的开发技能&#xff01; 什么是烹饪模拟游戏&#xff1f; 近年来&#xff0c;随着《…

【JavaScript】数组 ② ( JavaScript 数组索引 | JavaScript 遍历数组 | 使用 for 循环遍历数组 )

文章目录 一、JavaScript 数组索引1、数组索引2、数组索引 - 代码示例 二、JavaScript 遍历数组1、使用 for 循环遍历数组2、使用 for 循环遍历数组 - 代码示例 一、JavaScript 数组索引 1、数组索引 在 JavaScript 中 , 数组 的 " 索引 " 又称为 " 下标 "…

考研数学|武忠祥学习包搭配《660》和《880》

一、660、880、三大计算简单分析 660题 这本题册具有高难度、综合度和深度&#xff0c;属于高质量的题材。我建议不要在基础阶段就着手解决其中的660题&#xff0c;因为这可能会影响你的信心。相反&#xff0c;你可以在基础阶段完成一轮学习后&#xff0c;将这些题目留到强化…

爬取肯德基餐厅查询中指定地点的餐厅数据

进入肯德基官网 代码编写 import requests import jsonif __name__ __main__:get_url http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?opkeywordheaders {User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/1…

极速体验DolphinScheduler 3.2.1 Standalone 版[一]

文章目录 极速体验DolphinScheduler 3.2.1 Standalone 版前置准备工作启动 DolphinScheduler Standalone Server解压并启动 DolphinScheduler登录 DolphinScheduler 启停服务配置数据库 极速体验DolphinScheduler 3.2.1 Standalone 版 Standalone 仅适用于 DolphinScheduler 的…

Dify安装使用说明

dify功能简介 dify可以说是一个功能不错的LLMOps&#xff0c;可以通过dify集中管理模型&#xff0c;可以通过界面创建AI应用&#xff0c;可以上传文档形成知识库&#xff0c;可以创建自定义工具&#xff08;API&#xff09;&#xff0c;并可以对外提供API。 相关功能类似Open…

电源噪声的起因及危害

对造成电源不稳定的根源进行简单分析如下,主要在于两个方面:一是器件高速开关状态下,瞬态的交变电流过大;二是电流回路上存在的电感。从表现形式上来看又可以分为三类:同步开关噪声(SSN),有时被称为Δi噪声,地弹(Ground bounce)现象也可归于此类(图1-a);非理想电…

题目 2898: 二维数组回形遍历

题目描述: 给定一个row行col列的整数数组array&#xff0c;要求从array[0][0]元素开始&#xff0c;按回形从外向内顺时针顺序遍历整个数组。如图所示&#xff1a; 代码: package lanqiao;import java.math.BigInteger; import java.util.*;public class Main {public static …