Vue2+Vue3基础入门到实战项目(前接六 副线一)—— 面经 项目

day1

接口文档地址:https://www.apifox.cn/apidoc/project-934563/api-20384515

一、项目功能演示

1.目标

启动准备好的代码,演示移动端面经内容,明确功能模块

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.项目收获

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

二、项目创建目录初始化

vue-cli 建项目

1.安装脚手架 (已安装)

npm i @vue/cli -g

2.创建项目

vue create hm-vant-h5
  • 选项
Vue CLI v5.0.8
? Please pick a preset:Default ([Vue 3] babel, eslint)Default ([Vue 2] babel, eslint)
> Manually select features     选自定义
  • 手动选择功能

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 选择vue的版本
  3.x
> 2.x
  • 是否使用history模式

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 选择css预处理

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 选择eslint的风格 (eslint 代码规范的检验工具,检验代码是否符合规范)
  • 比如:const age = 18; => 报错!多加了分号!后面有工具,一保存,全部格式化成最规范的样子

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 选择校验的时机 (直接回车)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 选择配置文件的生成方式 (直接回车)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 是否保存预设,下次直接使用? => 不保存,输入 N

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 等待安装,项目初始化完成

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 启动项目
npm run serve

三、ESlint代码规范及手动修复

代码规范:一套写代码的约定规则。例如:赋值符号的左右是否需要空格?一句结束是否是要加;?…

没有规矩不成方圆

ESLint:是一个代码检查工具,用来检查你的代码是否符合指定的规则(你和你的团队可以自行约定一套规则)。在创建项目时,我们使用的是 JavaScript Standard Style 代码风格的规则。

1.JavaScript Standard Style 规范说明

建议把:https://standardjs.com/rules-zhcn.html 看一遍,然后在写的时候, 遇到错误就查询解决。

下面是这份规则中的一小部分:

  • 字符串使用单引号 – 需要转义的地方除外
  • 无分号 – 这没什么不好。不骗你!
  • 关键字后加空格 if (condition) { ... }
  • 函数名后加空格 function name (arg) { ... }
  • 坚持使用全等 === 摒弃 == 一但在需要检查 null || undefined 时可以使用 obj == null

2.代码规范错误

如果你的代码不符合standard的要求,eslint会跳出来刀子嘴,豆腐心地提示你。

下面我们在main.js中随意做一些改动:添加一些空行,空格。

import Vue from 'vue'
import App from './App.vue'import './styles/index.less'
import router from './router'
Vue.config.productionTip = falsenew Vue ( {render: h => h(App),router
}).$mount('#app')

按下保存代码之后:

你将会看在控制台中输出如下错误:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

eslint 是来帮助你的。心态要好,有错,就改。

3.手动修正

根据错误提示来一项一项手动修正。

如果你不认识命令行中的语法报错是什么意思,你可以根据错误代码(func-call-spacing, space-in-parens,…)去 ESLint 规则列表中查找其具体含义。

打开 ESLint 规则表,使用页面搜索(Ctrl + F)这个代码,查找对该规则的一个释义。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

四、通过eslint插件来实现自动修正

  1. eslint会自动高亮错误显示
  2. 通过配置,eslint会自动帮助我们修复错误
  • 如何安装

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 如何配置
// 当保存的时候,eslint自动帮我们修复错误
"editor.codeActionsOnSave": {"source.fixAll": true
},
// 保存代码,不自动格式化
"editor.formatOnSave": false
  • 注意:eslint的配置文件必须在根目录下,这个插件才能才能生效。打开项目必须以根目录打开,一次打开一个项目
  • 注意:使用了eslint校验之后,把vscode带的那些格式化工具全禁用了 Beatify

settings.json 参考

{"window.zoomLevel": 2,"workbench.iconTheme": "vscode-icons","editor.tabSize": 2,"emmet.triggerExpansionOnTab": true,// 当保存的时候,eslint自动帮我们修复错误"editor.codeActionsOnSave": {"source.fixAll": true},// 保存代码,不自动格式化"editor.formatOnSave": false
}

五、调整初始化目录结构

强烈建议大家严格按照老师的步骤进行调整,为了符合企业规范

为了更好的实现后面的操作,我们把整体的目录结构做一些调整。

目标:

  1. 删除初始化的一些默认文件
  2. 修改没删除的文件
  3. 新增我们需要的目录结构

1.删除文件

  • src/assets/logo.png
  • src/components/HelloWorld.vue
  • src/views/AboutView.vue
  • src/views/HomeView.vue

2.修改文件

main.js 不需要修改

router/index.js

删除默认的路由配置

import Vue from 'vue'
import VueRouter from 'vue-router'Vue.use(VueRouter)const routes = [
]const router = new VueRouter({routes
})export default router

App.vue

<template><div id="app"><router-view/></div>
</template>

3.新增目录

  • src/api 目录
    • 存储接口模块 (发送ajax请求接口的模块)
  • src/utils 目录
    • 存储一些工具模块 (自己封装的方法)

目录效果如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

六、vant组件库及Vue周边的其他组件库

组件库:第三方封装好了很多很多的组件,整合到一起就是一个组件库。

https://vant-contrib.gitee.io/vant/v2/#/zh-CN/

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

比如日历组件、键盘组件、打分组件、登录组件等

组件库并不是唯一的,常用的组件库还有以下几种:

pc: element-ui element-plus iview ant-design

移动:vant-ui Mint UI (饿了么) Cube UI (滴滴)

七、全部导入和按需导入的区别

目标:明确 全部导入按需导入 的区别

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

区别:

1.全部导入会引起项目打包后的体积变大,进而影响用户访问网站的性能

2.按需导入只会导入你使用的组件,进而节约了资源

八、全部导入

  • 安装vant-ui
yarn add vant@latest-v2
// 或者 npm i vant@latest-v2
  • 在main.js中
import Vant from 'vant';
import 'vant/lib/index.css';
// 把vant中所有的组件都导入了
Vue.use(Vant)
  • 即可使用
<van-button type="primary">主要按钮</van-button>
<van-button type="info">信息按钮</van-button>

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

vant-ui提供了很多的组件,全部导入,会导致项目打包变得很大。

九、按需导入

  • 安装vant-ui
npm i vant@latest-v2  或  yarn add vant@latest-v2
  • 安装一个插件
npm i babel-plugin-import -D
  • babel.config.js中配置
module.exports = {presets: ['@vue/cli-plugin-babel/preset'],plugins: [['import', {libraryName: 'vant',libraryDirectory: 'es',style: true}, 'vant']]
}
  • 按需加载,在main.js
import { Button, Icon } from 'vant'Vue.use(Button)
Vue.use(Icon)
  • app.vue中进行测试
<van-button type="primary">主要按钮</van-button>
<van-button type="info">信息按钮</van-button>
<van-button type="default">默认按钮</van-button>
<van-button type="warning">警告按钮</van-button>
<van-button type="danger">危险按钮</van-button>
  • 把引入组件的步骤抽离到单独的js文件中比如 utils/vant-ui.js
import { Button, Icon } from 'vant'Vue.use(Button)
Vue.use(Icon)

main.js中进行导入

// 导入按需导入的配置文件
import '@/utils/vant-ui'

十、项目中的vw适配

官方说明:https://vant-contrib.gitee.io/vant/v2/#/zh-CN/advanced-usage

yarn add postcss-px-to-viewport@1.1.1 -D
  • 项目根目录, 新建postcss的配置文件postcss.config.js
// postcss.config.js
module.exports = {plugins: {'postcss-px-to-viewport': {viewportWidth: 375,},},
};

viewportWidth:设计稿的视口宽度

  1. vant-ui中的组件就是按照375的视口宽度设计的
  2. 恰好面经项目中的设计稿也是按照375的视口宽度设计的,所以此时 我们只需要配置375就可以了
  3. 如果设计稿不是按照375而是按照750的宽度设计,那此时这个值该怎么填呢?

十一、路由配置-一级路由

但凡是单个页面,独立展示的,都是一级路由

路由设计:

  • 登录页 (一级) Login
  • 注册页(一级) Register
  • 文章详情页(一级) Detail
  • 首页(一级) Layout
    • 面经(二级)Article
    • 收藏(二级)Collect
    • 喜欢(二级)Like
    • 我的(二级)My

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

一级路由

router/index.js配置一级路由, 一级views组件于准备好的中直接 CV 即可

import Vue from 'vue'
import VueRouter from 'vue-router'
import Login from '@/views/Login'
import Register from '@/views/Register'
import Detail from '@/views/Detail'
import Layout from '@/views/Layout'
Vue.use(VueRouter)const router = new VueRouter({routes: [{ path: '/login', component: Login },{ path: '/register', component: Register },{ path: '/article/:id', component: Detail },{path: '/',component: Layout}]
})
export default router

清理 App.vue

<template><div id="app"><router-view/></div>
</template><script>
export default {created () {}
}
</script>

十二、路由配置-tabbar标签页

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

https://vant-contrib.gitee.io/vant/v2/#/zh-CN/tabbar

vant-ui.js 引入组件

import { Button, Icon, Tabbar, TabbarItem } from 'vant'
Vue.use(Tabbar)
Vue.use(TabbarItem)

layout.vue

  1. 复制官方代码
  2. 修改显示文本及显示的图标
<template><div class="layout-page">首页架子 - 内容区域 <van-tabbar><van-tabbar-item icon="notes-o">面经</van-tabbar-item><van-tabbar-item icon="star-o">收藏</van-tabbar-item><van-tabbar-item icon="like-o">喜欢</van-tabbar-item><van-tabbar-item icon="user-o">我的</van-tabbar-item></van-tabbar></div>
</template>

十三、路由配置-配置主题色

整体网站风格,其实都是橙色的,可以通过变量覆盖的方式,制定主题色

https://vant-contrib.gitee.io/vant/v2/#/zh-CN/theme

babel.config.js 制定样式路径

module.exports = {presets: ['@vue/cli-plugin-babel/preset'],plugins: [['import', {libraryName: 'vant',libraryDirectory: 'es',// 指定样式路径style: (name) => `${name}/style/less`}, 'vant']]
}

vue.config.js 覆盖变量

const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({transpileDependencies: true,css: {loaderOptions: {less: {lessOptions: {modifyVars: {// 直接覆盖变量'blue': '#FA6D1D',},},},},},
})

重启服务器生效!

十四、路由配置-二级路由

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1.router/index.js配置二级路由

在准备好的代码中去复制对应的组件即可

import Vue from 'vue'
import VueRouter from 'vue-router'
import Login from '@/views/Login'
import Register from '@/views/Register'
import Detail from '@/views/Detail'
import Layout from '@/views/Layout'import Like from '@/views/Like'
import Article from '@/views/Article'
import Collect from '@/views/Collect'
import User from '@/views/User'
Vue.use(VueRouter)const router = new VueRouter({routes: [{ path: '/login', component: Login },{ path: '/register', component: Register },{ path: '/article/:id', component: Detail },{ path: '/',component: Layout,redirect: '/article',children: [{ path: 'article', component: Article },{ path: 'like', component: Like },{ path: 'collect', component: Collect },{ path: 'user', component: User }]}]
})export default router

2.layout.vue 配置路由出口, 配置 tabbar

<template><div class="layout-page">//路由出口<router-view></router-view> <van-tabbar route><van-tabbar-item to="/article" icon="notes-o">面经</van-tabbar-item><van-tabbar-item to="/collect" icon="star-o">收藏</van-tabbar-item><van-tabbar-item to="/like" icon="like-o">喜欢</van-tabbar-item><van-tabbar-item to="/user" icon="user-o">我的</van-tabbar-item></van-tabbar></div>
</template>

十五、登录静态布局

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

使用组件

  • van-nav-bar
  • van-form
  • van-field
  • van-button

vant-ui.js 注册

import Vue from 'vue'
import {NavBar,Form,Field
} from 'vant'
Vue.use(NavBar)
Vue.use(Form)
Vue.use(Field)

Login.vue 使用

<template><div class="login-page"><!-- 导航栏部分 --><van-nav-bar title="面经登录" /><!-- 一旦form表单提交了,就会触发submit,可以在submit事件中根据拿到的表单提交信息,发送axios请求--><van-form @submit="onSubmit"><!-- 输入框组件 --><!-- \w 字母数字_   \d 数字0-9 --><van-fieldv-model="username"name="username"label="用户名"placeholder="用户名":rules="[{ required: true, message: '请填写用户名' },{ pattern: /^\w{5,}$/, message: '用户名至少包含5个字符' }]"/><van-fieldv-model="password"type="password"name="password"label="密码"placeholder="密码":rules="[{ required: true, message: '请填写密码' },{ pattern: /^\w{6,}$/, message: '密码至少包含6个字符' }]"/><div style="margin: 16px"><van-button block type="info" native-type="submit">提交</van-button></div></van-form></div>
</template><script>
export default {name: 'LoginPage',data () {return {username: 'zhousg',password: '123456'}},methods: {onSubmit (values) {console.log('submit', values)}}
}
</script>

login.vue添加 router-link 标签(跳转到注册)

<template><div class="login-page"><van-nav-bar title="面经登录" /><van-form @submit="onSubmit">...</van-form><router-link class="link" to="/register">注册账号</router-link></div>
</template>

login.vue调整样式

<style lang="less" scoped>
.link {color: #069;font-size: 12px;padding-right: 20px;float: right;
}
</style>

十六、登录表单中的细节分析

  1. @submit事件:当点击提交按钮时会自动触发submit事件
  2. v-model双向绑定:会自动把v-model后面的值和文本框中的值进行双向绑定
  3. name属性:收集的key的值,要和接口文档对应起来
  4. label:输入的文本框的title
  5. :rules: 表单的校验规则
  6. placeholder: 文本框的提示语

十七、注册静态布局

Register.vue

<template><div class="login-page"><van-nav-bar title="面经注册" /><van-form @submit="onSubmit"><van-fieldv-model="username"name="username"label="用户名"placeholder="用户名":rules="[{ required: true, message: '请填写用户名' },{ pattern: /^\w{5,}$/, message: '用户名至少包含5个字符' }]"/><van-fieldv-model="password"type="password"name="password"label="密码"placeholder="密码":rules="[{ required: true, message: '请填写密码' },{ pattern: /^\w{6,}$/, message: '密码至少包含6个字符' }]"/><div style="margin: 16px"><van-button block type="primary" native-type="submit">注册</van-button></div></van-form><router-link class="link" to="/login">有账号,去登录</router-link></div>
</template><script>
export default {name: 'Register-Page',data () {return {username: '',password: ''}},methods: {onSubmit (values) {console.log('submit', values)}}
}
</script><style lang="less" scoped>
.link {color: #069;font-size: 12px;padding-right: 20px;float: right;
}
</style>

十八、request模块 - axios封装

接口文档地址:https://apifox.com/apidoc/project-934563/api-20384515

基地址:http://interview-api-t.itheima.net/h5/

目标:将 axios 请求方法,封装到 request 模块

我们会使用 axios 来请求后端接口, 一般都会对 axios 进行一些配置 (比如: 配置基础地址,请求响应拦截器等等)

一般项目开发中, 都会对 axios 进行基本的二次封装, 单独封装到一个模块中, 便于使用

  1. 安装 axios
npm i axios
  1. 新建 utils/request.js 封装 axios 模块

    利用 axios.create 创建一个自定义的 axios 来使用

    http://www.axios-js.com/zh-cn/docs/#axios-create-config

/* 封装axios用于发送请求 */
import axios from 'axios'// 创建一个新的axios实例
const request = axios.create({baseURL: 'http://interview-api-t.itheima.net/h5/',timeout: 5000
})// 添加请求拦截器
request.interceptors.request.use(function (config) {// 在发送请求之前做些什么return config
}, function (error) {// 对请求错误做些什么return Promise.reject(error)
})// 添加响应拦截器
request.interceptors.response.use(function (response) {// 对响应数据做点什么return response.data
}, function (error) {// 对响应错误做点什么return Promise.reject(error)
})export default request
  1. 注册测试
// 监听表单的提交,形参中:可以获取到输入框的值
async onSubmit (values) {console.log('submit', values)const res = await request.post('/user/register', values)console.log(res)
}

十九、封装api接口 - 注册功能

1.目标:将请求封装成方法,统一存放到 api 模块,与页面分离

2.原因:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

以前的模式:

  • 页面中充斥着请求代码,
  • 可阅读性不高
  • 相同的请求没有复用请求没有统一管理

3.期望:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 请求与页面逻辑分离
  • 相同的请求可以直接复用请求
  • 进行了统一管理

4.具体实现

新建 api/user.js 提供注册 Api 函数

import request from '@/utils/request'// 注册接口
export const register = (data) => {return request.post('/user/register', data)
}

register.vue页面中调用测试

methods: {async onSubmit (values) {// 往后台发送注册请求了await register(values)alert('注册成功')this.$router.push('/login')}
}

二十、toast 轻提示

https://vant-contrib.gitee.io/vant/v2/#/zh-CN/toast

两种使用方式

  1. 组件内js文件内 导入,调用
import { Toast } from 'vant';
Toast('提示内容');
  1. **组件内 **通过this直接调用

main.js

import { Toast } from 'vant';
Vue.use(Toast)
this.$toast('提示内容')

代码演示

this.$toast.loading({message:'拼命加载中...',forbidClick:true
})
try{await register(values)this.$toast.success('注册成功')this.$router.push('/login')
}catch(e){this.$toast.fail('注册失败')
}

二十一、响应拦截器统一处理错误提示

响应拦截器是咱们拿到数据的第一个“数据流转站”

在这里插入图片描述

import { Toast } from 'vant'...// 添加响应拦截器
request.interceptors.response.use(function (response) {// 对响应数据做点什么return response.data
}, function (error) {if (error.response) {// 有错误响应, 提示错误提示Toast(error.response.data.message)}// 对响应错误做点什么return Promise.reject(error)
})

二十二、封装api接口 - 登录功能

api/user.js 提供登录 Api 函数

// 登录接口
export const login = (data) => {return request.post('/user/login', data)
}

login.vue 登录功能

import { login } from '@/api/user'methods: {async onSubmit (values) {const { data } = await login(values)this.$toast.success('登录成功')localStorage.setItem('vant-mobile-exp-token', data.token)this.$router.push('/')}
}

二十三、local模块 - 本地存储

新建 utils/storage.js

const KEY = 'vant-mobile-exp-token'// 直接用按需导出,可以导出多个
// 获取
export const getToken = () => {return localStorage.getItem(KEY)
}// 设置
export const setToken = (newToken) => {localStorage.setItem(KEY, newToken)
}// 删除
export const delToken = () => {localStorage.removeItem(KEY)
}

登录完成存储token到本地

import { login } from '@/api/user'
import { setToken } from '@/utils/storage'methods: {async onSubmit (values) {const { data } = await login(values)setToken(data.token)this.$toast.success('登录成功')this.$router.push('/')}
}

day2

一、全局前置守卫-语法认识

这个 面经移动端 项目,只对 登录用户 开放,如果未登录,一律拦截到登录

  1. 如果访问的是 首页, 无token, 拦走

  2. 如果访问的是 列表页,无token, 拦走

  3. 如果访问的是 详情页,无token, 拦走

分析:哪些页面,是不需要登录,就可以访问的! => 注册登录 (白名单 - 游客可以随意访问的)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

路由导航守卫 - 全局前置守卫

  • 访问的路径一旦被路由规则匹配到,都会先经过全局前置守卫

  • 只有全局前置守卫放行,才会真正解析渲染组件,才能看到页面内容

router/index.js

router.beforeEach((to, from, next) => {// 1. to   往哪里去, 到哪去的路由信息对象  // 2. from 从哪里来, 从哪来的路由信息对象// 3. next() 是否放行//    如果next()调用,就是放行//    next(路径) 拦截到某个路径页面
})

二、全局前置守卫-访问拦截处理

拦截或放行的关键点? → 用户是否有登录权证 token

核心逻辑:

  1. 判断用户有没有token, 有token, 直接放行 (有身份的人,想去哪就去哪~)
  2. 没有token(游客),如果是白名单中的页面,直接放行
  3. 否则,无token(游客),且在访问需要权限访问的页面,直接拦截到登录

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

// 全局前置守卫:
// 1. 所有的路由一旦被匹配到,在真正渲染解析之前,都会先经过全局前置守卫
// 2. 只有全局前置守卫放行,才能看到真正的页面// 任何路由,被解析访问前,都会先执行这个回调
// 1. from 你从哪里来, 从哪来的路由信息对象
// 2. to   你往哪里去, 到哪去的路由信息对象
// 3. next() 是否放行,如果next()调用,就是放行 => 放你去想去的页面
//    next(路径) 拦截到某个路径页面
import { getToken } from '@/utils/storage'const whiteList = ['/login', '/register'] // 白名单列表,记录无需权限访问的所有页面router.beforeEach((to, from, next) => {const token = getToken()// 如果有token,直接放行if (token) {next()} else {// 没有token的人, 看看你要去哪// (1) 访问的是无需授权的页面(白名单),也是放行//     就是判断,访问的地址,是否在白名单数组中存在 includesif (whiteList.includes(to.path)) {next()} else {// (2) 否则拦截到登录next('/login')}}
})

三、面经列表-认识Cell组件-准备基础布局

1.认识静态结构外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.注册组件:

  • van-cell
import Vue from 'vue'
import { Cell } from 'vant'
Vue.use(Cell)

3.静态结构 Article.vue

<template><div class="article-page"><nav class="my-nav van-hairline--bottom"><ahref="javascript:;">推荐</a><ahref="javascript:;">最新</a><div class="logo"><img src="@/assets/logo.png" alt=""></div></nav><van-cell class="article-item" ><template #title><div class="head"><img src="http://teachoss.itheima.net/heimaQuestionMiniapp/%E5%AE%98%E6%96%B9%E9%BB%98%E8%AE%A4%E5%A4%B4%E5%83%8F%402x.png" alt="" /><div class="con"><p class="title van-ellipsis">宇宙头条校招前端面经</p><p class="other">不风流怎样倜傥 | 2022-01-20 00-00-00</p></div></div></template><template #label><div class="body van-multi-ellipsis--l2">笔者读大三, 前端小白一枚, 正在准备春招, 人生第一次面试, 投了头条前端, 总共经历了四轮技术面试和一轮hr面, 不多说, 直接上题&nbsp;一面</div><div class="foot">点赞 46 | 浏览 332</div></template></van-cell></div>
</template><script>
export default {name: 'article-page',data () {return {}},methods: {}
}
</script><style lang="less" scoped>
.article-page {margin-bottom: 50px;margin-top: 44px;.my-nav {height: 44px;position: fixed;left: 0;top: 0;width: 100%;z-index: 999;background: #fff;display: flex;align-items: center;> a {color: #999;font-size: 14px;line-height: 44px;margin-left: 20px;position: relative;transition: all 0.3s;&::after {content: '';position: absolute;left: 50%;transform: translateX(-50%);bottom: 0;width: 0;height: 2px;background: #222;transition: all 0.3s;}&.active {color: #222;&::after {width: 14px;}}}.logo {flex: 1;display: flex;justify-content: flex-end;> img {width: 64px;height: 28px;display: block;margin-right: 10px;}}}
}
.article-item {.head {display: flex;img {width: 40px;height: 40px;border-radius: 50%;overflow: hidden;}.con {flex: 1;overflow: hidden;padding-left: 10px;p {margin: 0;line-height: 1.5;&.title {width: 280px;}&.other {font-size: 10px;color: #999;}}}}.body {font-size: 14px;color: #666;line-height: 1.6;margin-top: 10px;}.foot {font-size: 12px;color: #999;margin-top: 10px;}
}
</style>

四、封装 ArticleItem 组件

说明:每个文章列表项,其实就是一个整体,封装成一个组件 → 可阅读性 & 复用性

步骤:

  • 新建 components/ArticleItem.vue 组件,贴入内容
  • 注册成全局组件
  • Article.vue 页面中应用

新建 components/ArticleItem.vue 组件

<template><van-cell class="article-item"><template #title><div class="head"><img  src="http://teachoss.itheima.net/heimaQuestionMiniapp/%E5%AE%98%E6%96%B9%E9%BB%98%E8%AE%A4%E5%A4%B4%E5%83%8F%402x.png"alt=""/><div class="con"><p class="title van-ellipsis">宇宙头条校招前端面经</p><p class="other">不风流怎样倜傥 | 2022-01-20 00-00-00</p></div></div></template><template #label><div class="body van-multi-ellipsis--l2">笔者读大三, 前端小白一枚, 正在准备春招, 人生第一次面试, 投了头条前端,总共经历了四轮技术面试和一轮hr面, 不多说, 直接上题&nbsp;一面</div><div class="foot">点赞 46 | 浏览 332</div></template></van-cell>
</template><script>
export default {name: 'ArticleItem'
}
</script><style lang="less" scoped>
.article-item {.head {display: flex;img {width: 40px;height: 40px;border-radius: 50%;overflow: hidden;}.con {flex: 1;overflow: hidden;padding-left: 10px;p {margin: 0;line-height: 1.5;&.title {width: 280px;}&.other {font-size: 10px;color: #999;}}}}.body {font-size: 14px;color: #666;line-height: 1.6;margin-top: 10px;}.foot {font-size: 12px;color: #999;margin-top: 10px;}
}
</style>

注册成全局组件使用

import ArticleItem from '@/components/ArticleItem.vue'
Vue.component('ArticleItem', ArticleItem)

Article.vue页面中

<template><div class="article-page">... <ArticleItem></ArticleItem></div>
</template>

五、封装 api 接口-获取文章列表数据

接口:https://apifox.com/apidoc/project-934563/api-20384521

1.新建 api/article.js 提供接口函数

import request from '@/utils/request'export const getArticles = (obj) => {return request.get('/interview/query', {params: {current: obj.current,sorter: obj.sorter,pageSize: 10}})
}

2.页面中调用测试

import { getArticles } from '@/api/article'
export default {name: 'article-page',data () {return {}},async created () {const res = await getArticles({current: 1,sorter: 'weight_desc'})console.log(res)},methods: {}
}

3.发现 401 错误, 通过 headers 携带 token

注意:这个token,需要拼上前缀 Bearer token标识前缀

// 封装接口,获取文章列表
export const getArticles = (obj) => {const token = getToken()return request.get('/interview/query', {params: {current: obj.current, // 当前页pageSize: 10, // 每页条数sorter: obj.sorter // 排序字段 =>  传"weight_desc" 获取 推荐, "不传" 获取 最新},headers: {// 注意 Bearer 和 后面的空格不能删除,为后台的token辨识Authorization: `Bearer ${token}`}})
}

六、请求拦截器-携带 token

utils/request.js

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

每次自己携带token太麻烦,通过请求拦截器统一携带token更方便

import { getToken } from './storage'// 添加请求拦截器
request.interceptors.request.use(function (config) {// 在发送请求之前做些什么const token = getToken()if (token) {config.headers.Authorization = `Bearer ${token}`}return config
}, function (error) {// 对请求错误做些什么return Promise.reject(error)
})

七、响应拦截器-处理token过期

说明:token 是有过期时间的 (6h),一旦 过期 或 失效 就无法正确获取到数据!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

utils/request.js

// 添加响应拦截器
request.interceptors.response.use(function (response) {// 对响应数据做点什么return response.data
}, function (error) {if (error.response) {// 有错误响应, 提示错误提示if (error.response.status === 401) {delToken()router.push('/login')} else {Toast(error.response.data.message)}}// 对响应错误做点什么return Promise.reject(error)
})

八、面经列表-动态渲染列表

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

article.vue

存储数据

import {getArticles} from '@/api/article'
data () {return {list: [],current: 1,sorter: 'weight_desc'}
},
async created () {const { data } = await getArticles({current: this.current,sorter: this.sorter})this.list = data.data.rows
},

v-for循环展示

<template><div class="article-page">...<ArticleItem v-for="(item,i) in list" :key="item.id" :item="item"></ArticleItem></div>
</template>

子组件接收渲染

<template><van-cell class="article-item" @click="$router.push(`/detail/${item.id}`)"><template #title><div class="head"><img :src="item.avatar" alt="" /><div class="con"><p class="title van-ellipsis">{{ item.stem }}</p><p class="other">{{ item.creator }} | {{ item.createdAt }}</p></div></div></template><template #label><div class="body van-multi-ellipsis--l2" v-html="item.content"></div><div class="foot">点赞 {{ item.likeCount }} | 浏览 {{ item.views }}</div></template></van-cell>
</template><script>
export default {name: 'ArticleItem',props: {item: {type: Object,default: () => ({})}}
}
</script><style lang="less" scoped>
.article-item {.head {display: flex;img {width: 40px;height: 40px;border-radius: 50%;overflow: hidden;}.con {flex: 1;overflow: hidden;padding-left: 10px;p {margin: 0;line-height: 1.5;&.title {width: 280px;}&.other {font-size: 10px;color: #999;}}}}.body {font-size: 14px;color: #666;line-height: 1.6;margin-top: 10px;}.foot {font-size: 12px;color: #999;margin-top: 10px;}
}
</style>

九、面经列表-响应拦截器-简化响应

// 添加响应拦截器
instance.interceptors.response.use(function (response) {// 对响应数据做点什么return response.data
}, function (error) {// console.log(error)// 有错误响应,后台正常返回了错误信息if (error.response) {if (error.response.status === 401) {// 清除掉无效的tokendelToken()// 拦截到登录router.push('/login')} else {// 有错误响应,提示错误消息// this.$toast(error.response.data.message)Toast(error.response.data.message)}}// 对响应错误做点什么return Promise.reject(error)
})

Login.vue

setToken(data.token)

Article.vue

async created () {// 获取推荐的,第1页的10条数据const res = await getArticles({current: this.current,sorter: this.sorter})this.list = res.data.rows
},

十、面经列表-分页加载更多

https://vant-contrib.gitee.io/vant/v2/#/zh-CN/list

<van-listv-model="loading":finished="finished"finished-text="没有更多了"@load="onLoad"
><ArticleItem v-for="(item,i) in list" :key="i" :item="item"></ArticleItem>
</van-list>data () {return {list: [],current: 1,sorter: 'weight_desc',loading: false,finished: false}
},methods: {async onLoad () {const { data } = await getArticles({current: this.current,sorter: this.sorter})this.list = data.rows}
}

加载完成,重置 loading, 累加数据,处理 finished

async onLoad () {const { data } = await getArticles({current: this.current,sorter: this.sorter})this.list.push(...data.rows)this.loading = falsethis.current++if (this.current > data.pageTotal) {this.finished = true}
}

十一、面经列表-推荐和更新

1.切换推荐和最新 获取不同的数据

2.切换推荐和最新 点击的tab页签应该高亮

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

article.vue

<a@click="changeSorter('weight_desc')":class="{ active: sorter === 'weight_desc' }"href="javascript:;">推荐</a
>
<a@click="changeSorter(null)":class="{ active: sorter === null }"href="javascript:;">最新</a
>

提供methods

changeSorter (value) {this.sorter = value// 重置所有条件this.current = 1 // 排序条件变化,重新从第一页开始加载this.list = []this.finished = false // finished重置,重新有数据可以加载了// this.loading = false// 手动加载更多// 手动调用了加载更多,也需要手动将loading改成true,表示正在加载中(避免重复触发)this.loading = truethis.onLoad()
}

十二、面经详情-动态路由传参-请求渲染

1.跳转路由传参

核心知识点:跳转路由传参

准备动态路由 (已准备)

const router = new VueRouter({routes: [...,{ path: '/article/:id', component: Detail },{path: '/',component: Layout,redirect: '/article',children: [...]}]
})

点击跳转 article.vue

<template><!-- 文章区域 --><van-cell class="article-item" @click="$router.push(`/detail/${item.id}`)"><template #title>...</template><template #label>...</template></van-cell>
</template>

页面中获取参数

this.$route.params.id

2.动态渲染 (页面代码准备)

准备代码:

导入图标组件:

Vue.use(Icon)

静态结构:

<template><div class="detail-page"><van-nav-barleft-text="返回"@click-left="$router.back()"fixedtitle="面经详情"/><header class="header"><h1>大标题</h1><p>2050-04-06 | 300 浏览量 | 222 点赞数</p><p><img src="头像" alt="" /><span>作者</span></p></header><main class="body"><p>我是内容</p><p>我是内容</p><p>我是内容</p><p>我是内容</p></main><div class="opt"><van-icon class="active" name="like-o"/><van-icon name="star-o"/></div></div>
</template><script>
export default {name: 'detail-page',data () {return {article: {}}},async created () {},methods: {}
}
</script><style lang="less" scoped>
.detail-page {margin-top: 44px;overflow: hidden;padding: 0 15px;.header {h1 {font-size: 24px;}p {color: #999;font-size: 12px;display: flex;align-items: center;}img {width: 40px;height: 40px;border-radius: 50%;overflow: hidden;}}.opt {position: fixed;bottom: 100px;right: 0;> .van-icon {margin-right: 20px;background: #fff;width: 40px;height: 40px;line-height: 40px;text-align: center;border-radius: 50%;box-shadow: 2px 2px 10px #ccc;font-size: 18px;&.active {background: #FEC635;color: #fff;}}}
}
</style>

3.代码实现

3.1封装api接口函数

api/article.js

export const getArticleDetail = (id) => {return request.get('interview/show', {params: {id}})
}

3.2动态渲染

Detail.vue

<template><div class="detail-page"><van-nav-barleft-text="返回"@click-left="$router.back()"fixedtitle="面经详细"/><header class="header"><h1>{{ article.stem }}</h1><p>{{ article.createdAt }} | {{ article.views }} 浏览量 |{{ article.likeCount }} 点赞数</p><p><img :src="article.avatar" alt="" /><span>{{ article.creator }}</span></p></header><main class="body" v-html="article.content"></main><div class="opt"><van-icon :class="{active:article.likeFlag}" name="like-o"/><van-icon :class="{active:article.collectFlag}" name="star-o"/></div></div>
</template><script>
import { getArticleDetail } from '@/api/article'export default {name: 'detail-page',data () {return {article: {}}},async created () {this.article = {}const { data } = await getArticleDetail(this.$route.params.id)this.article = data},methods: {}
}
</script>

十三、面经详情-点赞收藏

封装准备接口

api/article.js

export const updateLike = (id) => {return request.post('interview/opt', {id,optType: 1 // 喜欢})
}export const updateCollect = (id) => {return request.post('interview/opt', {id,optType: 2 // 收藏})
}

Detail.vue

调用接口实现点赞收藏

<template><div class="detail-page"><van-nav-barleft-text="返回"@click-left="$router.back()"fixedtitle="面经详细"/><header class="header"><h1>{{ article.stem }}</h1><p>{{ article.createdAt }} | {{ article.views }} 浏览量 |{{ article.likeCount }} 点赞数</p><p><img :src="article.avatar" alt="" /><span>{{ article.creator }}</span></p></header><main class="body" v-html="article.content"></main><div class="opt"><van-icon @click="toggleLike" :class="{active:article.likeFlag}" name="like-o"/><van-icon @click="toggleCollect" :class="{active:article.collectFlag}" name="star-o"/></div></div>
</template><script>
import { getArticleDetail, updateCollect, updateLike } from '@/api/article';export default {name: 'detail-page',data() {return {article: {}};},async created() {this.article = {}const { data } = await getArticleDetail(this.$route.params.id)this.article = data;},methods: {async toggleLike () {await updateLike(this.article.id)this.article.likeFlag = !this.article.likeFlagif ( this.article.likeFlag ) {this.article.likeCount ++this.$toast.success('点赞成功')} else {this.article.likeCount --this.$toast.success('取消点赞')}},async toggleCollect () {await updateCollect(this.article.id)this.article.collectFlag = !this.article.collectFlagif ( this.article.collectFlag ) {this.$toast.success('收藏成功')} else {this.$toast.success('取消收藏')}}}
};
</script><style lang="less" scoped>
.detail-page {margin-top: 44px;overflow: hidden;padding: 0 15px;.header {h1 {font-size: 24px;}p {color: #999;font-size: 12px;display: flex;align-items: center;}img {width: 40px;height: 40px;border-radius: 50%;overflow: hidden;}}.opt {position: fixed;bottom: 100px;right: 0;> .van-icon {margin-right: 20px;background: #fff;width: 40px;height: 40px;line-height: 40px;text-align: center;border-radius: 50%;box-shadow: 2px 2px 10px #ccc;font-size: 18px;&.active {background: #FEC635;color: #fff;}}}
}
</style>

十四、我的收藏 (实战)

提供api方法

  • page: 表示当前页
  • optType:2 表示获取我的收藏数据

api/article.js

// 获取我的收藏
export const getArticlesCollect = (obj) => {return request.get('/interview/opt/list', {params: {page: obj.page, // 当前页pageSize: 5, // 可选optType: 2 // 表示收藏}})
}

collect.vue准备结构

<template><div class="collect-page"><van-nav-bar fixed title="我的收藏" /><van-listv-model="loading":finished="finished"finished-text="没有更多了"@load="onLoad"><ArticleItem v-for="(item, i) in list" :key="i" :item="item" /></van-list></div>
</template><script>
import { getArticlesCollect } from '@/api/article'
export default {name: 'collect-page',data () {return {list: [],loading: false,finished: false,page: 1}},methods: {async onLoad () {// 异步更新数据const { data } = await getArticlesCollect({ page: this.page })this.list.push(...data.rows)this.loading = falsethis.page++if (this.page > data.pageTotal) {this.finished = true}}}
}
</script><style lang="less" scoped>
.collect-page {margin-bottom: 50px;margin-top: 44px;
}
</style>

十五、我的喜欢 (快速实现)

准备api函数

  • page: 表示当前页
  • optType:1 表示获取我的喜欢数据

api/article.js

// 获取我的喜欢
export const getArticlesLike = (obj) => {return request.get('/interview/opt/list', {params: {page: obj.page, // 当前页pageSize: 5, // 可选optType: 1 // 表示喜欢}})
}

Like.vue请求渲染

<template><div class="like-page"><van-nav-bar fixed title="我的点赞" /><van-listv-model="loading":finished="finished"finished-text="没有更多了"@load="onLoad"><ArticleItem v-for="(item,i) in list" :key="i" :item="item" /></van-list></div>
</template><script>
import { getArticlesLike } from '@/api/article'
export default {name: 'like-page',data () {return {list: [],loading: false,finished: false,page: 1}},methods: {async onLoad () {// 异步更新数据const { data } = await getArticlesLike({ page: this.page })this.list.push(...data.rows)this.loading = falsethis.page++if (this.page > data.pageTotal) {this.finished = true}}}
}
</script><style lang="less" scoped>
.like-page {margin-bottom: 50px;margin-top: 44px;
}
</style>

十六、个人中心 (快速实现)

准备代码:

1 注册组件

import {Grid,GridItem,CellGroup
} from 'vant'Vue.use(Grid)
Vue.use(GridItem)
Vue.use(CellGroup)

2 准备api

api/user.js

// 获取用户信息
export const getUserInfo = () => {return request('/user/currentUser')
}

3 页面调用渲染

<template><div class="user-page"><div class="user"><img :src="avatar" alt="" /><h3>{{ username }}</h3></div><van-grid clickable :column-num="3" :border="false"><van-grid-item icon="clock-o" text="历史记录" to="/" /><van-grid-item icon="bookmark-o" text="我的收藏" to="/collect" /><van-grid-item icon="thumb-circle-o" text="我的点赞" to="/like" /></van-grid><van-cell-group class="mt20"><van-cell title="推荐分享" is-link /><van-cell title="意见反馈" is-link /><van-cell title="关于我们" is-link /><van-cell @click="logout" title="退出登录" is-link /></van-cell-group></div>
</template><script>
import { getUserInfo } from '@/api/user'
import { delToken } from '@/utils/storage'
export default {name: 'user-page',data () {return {username: '',avatar: ''}},async created () {const { data } = await getUserInfo()this.username = data.usernamethis.avatar = data.avatar},methods: {logout () {delToken()this.$router.push('/login')}}
}
</script><style lang="less" scoped>
.user-page {padding: 0 10px;background: #f5f5f5;height: 100vh;.mt20 {margin-top: 20px;}.user {display: flex;padding: 20px 0;align-items: center;img {width: 80px;height: 80px;border-radius: 50%;overflow: hidden;}h3 {margin: 0;padding-left: 20px;font-size: 18px;}}
}
</style>

十七、打包发布

vue脚手架只是开发过程中,协助开发的工具,当真正开发完了 => 脚手架不参与上线

参与上线的是 => 打包后的源代码

打包:

  • 将多个文件压缩合并成一个文件
  • 语法降级
  • less sass ts 语法解析, 解析成css

打包后,可以生成,浏览器能够直接运行的网页 => 就是需要上线的源码!

打包命令

vue脚手架工具已经提供了打包命令,直接使用即可。

yarn build

在项目的根目录会自动创建一个文件夹dist,dist中的文件就是打包后的文件,只需要放到服务器中即可。

配置publicPath

module.exports = {// 设置获取.js,.css文件时,是以相对地址为基准的。// https://cli.vuejs.org/zh/config/#publicpathpublicPath: './'
}

十八、路由懒加载

路由懒加载 & 异步组件, 不会一上来就将所有的组件都加载,而是访问到对应的路由了,才加载解析这个路由对应的所有组件

官网链接:https://router.vuejs.org/zh/guide/advanced/lazy-loading.html#%E4%BD%BF%E7%94%A8-webpack

当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。

const Detail = () => import('@/views/detail')
const Register = () => import('@/views/register')
const Login = () => import('@/views/login')
const Article = () => import('@/views/article')
const Collect = () => import('@/views/collect')
const Like = () => import('@/views/like')
const User = () => import('@/views/user')

PS: 如果想要手机上看到效果,可以将打包后的代码,上传到 gitee,利用 git pages 进行展示

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WebSocket的那些事(5-Spring STOMP支持之连接外部消息代理)

目录 一、序言二、开启RabbitMQ外部消息代理三、代码示例1、Maven依赖项2、相关实体3、自定义用户认证拦截器4、Websocket外部消息代理配置5、ChatController6、前端页面chat.html 四、测试示例1、群聊、私聊、后台定时推送测试2、登录RabbitMQ控制台查看队列信息 五、结语 一、…

第4章_瑞萨MCU零基础入门系列教程之瑞萨 MCU 源码设计规范

本教程基于韦东山百问网出的 DShanMCU-RA6M5开发板 进行编写&#xff0c;需要的同学可以在这里获取&#xff1a; https://item.taobao.com/item.htm?id728461040949 配套资料获取&#xff1a;https://renesas-docs.100ask.net 瑞萨MCU零基础入门系列教程汇总&#xff1a; ht…

deepin V23通过flathub安装steam畅玩游戏

deepin V23缺少32位库&#xff0c;在星火商店安装的steam,打开报错&#xff0c;无法使用&#xff01; 通过flathub网站安装steam,可以正常使用&#xff0c;详细教程如下&#xff1a; flathub网址&#xff1a;主页 | Flathub 注意&#xff1a;flathub下载速度慢&#xff0c;只…

Redis从基础到进阶篇(四)----性能调优、分布式锁与缓存问题

目录 一、Redis 集群演变 1.1 ReplicationSentinel*高可用 1.2 ProxyReplicationSentinel(仅仅了解) 1.3 Redis Cluster 集群 (重点&#xff09; 1.3.1 Redis-cluster架构图 1.3.2 工作原理 1.3.3 主从切换 1.3.4 副本漂移 1.3.5 分片漂移 二、Redis版本历史&#xf…

ODC现已开源:与开发者共创企业级的数据库协同开发工具

OceanBase 开发者中心&#xff08;OceanBase Developer Center&#xff0c;以下简称 ODC&#xff09;是一款开源的数据库开发和数据库管理协同工具&#xff0c;从首个版本上线距今已经发展了三年有余&#xff0c;ODC 逐步由一款专为 OceanBase 打造的开发者工具演进成为支持多数…

xCode14.3.1运行MonkeyDev出现“Executable Not Found“的解决办法

安装MonkeyDev遇到的坑 环境&#xff1a;Xcode Version 14.3.1 (14E300c) 错误提示 is not a valid path to an executable file. 报错 /Users/xxxx//Library/Developer/Xcode/DerivedData/MonTest-ccparhdyzjuqhjdergwrngpfwwoh/Build/Products/Debug-iphoneos/MonTest.app…

go-zerogo web集成redis实战

前言 上一篇&#xff1a;go-zero&go web集成JWT和cobra命令行工具实战 从零开始基于go-zero搭建go web项目实战-03集成redis实战 源码仓库地址 源码 https://gitee.com/li_zheng/treasure-box golang redis 客户端 Go-Redis 地址&#xff1a; GitHub: https://github.…

Maven 知识点总结

文章目录 Maven1、Maven 坐标2、Maven 仓库3、Maven 依赖依赖配置依赖范围依赖调解原则排除依赖 4、Maven 生命周期5、Maven 聚合与继承 Maven Maven是一个项目管理工具&#xff0c;它包含了项目对象模型&#xff08;POM&#xff1a;Project Object Model&#xff09;&#xf…

windows系统docker中将vue项目网站部署在nginx上

一、首先在windows系统上下载并安装docker&#xff0c;要下载windows版本 https://www.docker.com/products/docker-desktop/ PS&#xff1a;安装过程中需要WSL&#xff0c;我的是win11系统&#xff0c;直接提示了我安装就可以下一步了。其他windows系统版本我不知道是否需要单…

简化转换器:使用您理解的单词进行最先进的 NLP — 第 1 部分 — 输入

一、说明 变形金刚是一种深度学习架构&#xff0c;为人工智能的发展做出了杰出贡献。这是人工智能和整个技术领域的一个重要阶段&#xff0c;但也有点复杂。截至今天&#xff0c;变形金刚上有很多很好的资源&#xff0c;那么为什么要再制作一个呢&#xff1f;两个原因&#xff…

# Spring MVC与RESTful API:如何设计高效的Web接口

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

数学建模--K-means聚类的Python实现

目录 1.算法流程简介 2.1.K-mean算法核心代码 2.2.K-mean算法效果展示 3.1.肘部法算法核心代码 3.2.肘部法算法效果展示 1.算法流程简介 #k-means聚类方法 """ k-means聚类算法流程: 1.K-mean均值聚类的方法就是先随机选择k个对象作为初始聚类中心. 2.这…

AI伦理:科技发展中的人性之声

文章目录 AI伦理的关键问题1. 隐私问题2. 公平性问题3. 自主性问题4. 伦理教育问题 隐私问题的拓展分析数据收集和滥用隐私泄露和数据安全 公平性问题的拓展分析历史偏见和算法模型可解释性 自主性问题的拓展分析自主AI决策伦理框架 伦理教育的拓展分析伦理培训 结论 &#x1f…

vue学习之基本用法

1. 前期准备 安装vs code IDE&#xff0c;vs code 安装 插件 open in brower新建 vue-learning 文件夹vs code IDE打开文件夹 2. 基本用法 创建demo1.html文件,内容如下 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8&qu…

华为数据管理——《华为数据之道》

数据分析与开发 元数据是描述数据的数据&#xff0c;用于打破业务和IT之间的语言障碍&#xff0c;帮助业务更好地理解数据。 元数据是数据中台的重要的基础设施&#xff0c;元数据治理贯彻数据产生、加工、消费的全过程&#xff0c;沉淀了数据资产&#xff0c;搭建了技术和业务…

Tomcat配置ssl、jar包

Tomcat配置ssl 部署tomcat服务&#xff0c;项目做到用https访问&#xff0c;使用nginx去做&#xff0c;访问任意一个子网站&#xff0c;都是https 或者 医美项目需要 上传jdk 456 tomcat war包 [nginx-stable] namenginx stable repo baseurlhttp://nginx.org/packages/…

“内存炸弹”DDOS拒绝服务攻击

Windows平台演示 最早的内存炸弹是 zip 炸弹&#xff0c;也称为死亡 zip&#xff0c;它是一种恶意计算机文件&#xff0c;旨在使读取该文件的程序崩溃或瘫痪。zip 炸弹不会劫持程序的操作&#xff0c;而是利用解压缩压缩文件所需的时间、磁盘空间或内存。 zip 炸弹的一个示例…

关于 RK3568的linux系统killed用户应用进程(用户现象为崩溃) 的解决方法

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/132710642 红胖子网络科技博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬…

Linux权限的概念和管理

Linux权限的概念和管理 1. Linux权限的概念2. Linux权限管理2.1 文件访问者的分类&#xff08;人&#xff09;2.2 文件类型和访问权限&#xff08;事物属性&#xff09;2.2.1 文件类型2.2.2 基本权限 2.3 文件权限值的表示方法2.4文件访问权限的相关设置方法1. chmod&#xff0…

ESP32用作经典蓝牙串口透传模块与手机进行串口通信

ESP32用作经典蓝牙串口透传模块与手机进行串口通信 简介ESP32开发板Arduino程序手机与ESP32开发板进行蓝牙串口透传通信总结 简介 ESP32-WROOM-32模组集成了双模蓝牙包括传统蓝牙&#xff08;BR/EDR&#xff09;、低功耗蓝牙&#xff08;BLE&#xff09;和 Wi-Fi&#xff0c;具…