2.vue3医疗在线问诊项目 - _登录模块 ==> 代码片段、css变量主题定制、cp-nav-bar组件封装、svg打包精灵图插件、cp-icon组件封装、表单校验、密码登录、短信验证码登录及两者
2.医疗在线问诊项目 - _登录模块 ==> 代码片段、css变量主题定制、cp-nav-bar组件封装、svg打包精灵图插件、cp-icon组件封装、表单校验、密码登录、短信验证码登录及两者的切换
路由与组件{#router-and-component}
完成:路由规则的配置,基础组件结构,app组件路由出口
- 基础组件结构
views/Login/index.vue
<template><div class="login"><van-button type="primary">按钮</van-button><van-checkbox :checked="true">复选框</van-checkbox></div>
</template><style lang="scss" scoped></style>
- 路由规则的配置
router/index.ts
routes: [{ path: '/login', component: () => import('@/views/Login/index.vue') }]
- app组件路由出口
App.vue
<script setup lang="ts"></script><template><router-view></router-view>
</template>
疑问:
- vue 生成组件基础结构?
- 使用vscode代码片段,或插件
- vant 的主题色和项目的不一致?
- css变量定制主题
组件代码片段{#code-snippet}
配置:一个vue3页面的基础代码片段
- 打开代码片段设置界面:
- windows:ctrl + shift + p
- mac:cmmmand + shift + p
新建全局代码片段文件
拷贝一下代码,保存即可,输入v3t
"sfc-ts语法糖": {"scope": "vue,markdown","prefix": "v3t","body": ["<script setup lang='ts'>"," $2","</script>","","<template>"," <div>"," $1"," </div>","</template>","","<style lang='scss' scoped>","","</style>",]}
或者安装:Vue 3 Snippets 插件,快捷键可以看插件文档。
css变量主题定制{#css-var}
实现:使用css变量定制项目主题,和修改vant主题
- 定义和使用 css 变量
styles/main.scss
/**原生css变量的定义=》类似less/sass定义变量语法:1. 定义:--css变量名:css变量值2. 使用:var(--css变量名)作用域:1. 局部变量 =》 .类名 { }2. 全局变量 =》 :root { }
*/
:root {--main: #999;
}
a {color: var(--main)
}
- 定义项目的颜色风格,覆盖vant的主题色 官方文档
修改vant组件库主题思路❓:
**前提=》**vant组件库中所有组件用到的颜色、字体大小、间距等,都定义成全局的原生css变量
根据公司需求修改主题=》覆盖vant内置的全局css变量=》变量修改后,就会影响所有组件
styles/main.scss
:root:root {// 项目定义变量--cp-primary: #16c2a3;--cp-plain: #eaf8f6;--cp-orange: #fca21c;--cp-text1: #121826;--cp-text2: #3c3e42;--cp-text3: #6f6f6f;--cp-tag: #848484;--cp-dark: #979797;--cp-tip: #c3c3c5;--cp-disable: #d9dbde;--cp-line: #ededed;--cp-bg: #f6f7f9;--cp-price: #eb5757;// 覆盖vant主体色--van-primary-color: var(--cp-primary);// == vant组件变量 ==// 单元格上下间距--van-cell-vertical-padding: 14px;// 复选框大小--van-checkbox-size: 14px;// 默认按钮文字大小--van-button-normal-font-size: 16px;
}// 全局样式
body {font-size: 14px;color: var(--cp-text1);
}
a {color: var(--cp-text2);
}
h1,h2,h3,h4,h5,h6,p,ul,ol {margin: 0;padding: 0;
}// 全局覆盖van-tab样式
.van-tabs {.van-tabs__nav {padding: 0 0 15px 0;}.van-tabs__line {width: 20px;background-color: var(--cp-primary);}.van-tab {padding: 0 15px;}
}
说明❓:通过两个:root
覆盖vant变量
App.vue
<script setup lang="ts"></script><template><!-- 验证vant颜色被覆盖 --><van-button type="primary">按钮</van-button><a href="#">123</a>
</template><style scoped lang="scss">
// 使用 css 变量
a {color: var(--cp-primary);
}
</style>
cp-nav-bar 组件结构{#cp-nav-bar-html}
掌握:van-nav-bar组件的基础使用,封装成 cp-nav-bar 组件,作为项目通用组件
提取原因❓:
- 定制需求:api、style等
- 多页面使用:复用
组件使用:了解 van-nav-bar 组件的基本功能属性文档
抽离组件:components/cp-nav-bar.vue
<script setup lang="ts">
// 1. 已有的功能:返回图标,返回效果,固定定位(组件内部实现)
// 2. 使用组件时候才能确定的功能:标题,右侧文字,点击右侧文字行为(props传入)
const onClickLeft = () => {//
}
const onClickRight = () => {//
}
</script><template><van-nav-barleft-arrow@click-left="onClickLeft"fixedtitle="注册"right-text="注册"@click-right="onClickRight"></van-nav-bar>
</template><style lang="scss" scoped>
::v-deep() {.van-nav-bar {&__arrow {font-size: 18px;color: var(--cp-text1);}&__text {font-size: 15px;}}
}
</style>
提问:
- 怎么深度作用其他组件样式?
::v-deep(){ // 样式 }
cp-nav-bar 组件功能{#cp-nav-bar-logic}
实现:组件的返回功能,支持 title rightText 属性,支持 click-right 事件
封装需求❓:支持 title rightText 属性,支持 click-right 事件
components/cp-nav-bar.vue
<script setup lang="ts">
import { useRouter } from 'vue-router'//1. 已有的功能:返回图标,返回效果,固定定位(组件内部实现)
const router = useRouter()
const onClickLeft = () => {// 判断历史记录中是否有回退if (history.state?.back) {router.back()} else {router.push('/')}
}// 2. 使用组件时候才能确定的功能:标题,右侧文字,点击右侧文字行为(props传入)
defineProps<{title?: stringrightText?: string
}>()
const emit = defineEmits<{(e: 'click-right'): void
}>()
const onClickRight = () => {emit('click-right')
}
</script><template><van-nav-barleft-arrow@click-left="onClickLeft"fixed:title="title":right-text="rightText"@click-right="onClickRight"></van-nav-bar>
</template><style lang="scss" scoped>
::v-deep() {.van-nav-bar {&__arrow {font-size: 18px;color: var(--cp-text1);}&__text {font-size: 15px;}}
}
</style>
views/Login/index.vue
<script setup lang="ts"></script><template><div class="login"><cp-nav-bar title="登录"></cp-nav-bar></div>
</template><style lang="scss" scoped></style>
提问:
怎么在项目中判断是否可以回退?
history.state?.back
怎么定义属性,怎么定义事件
defineProps
defineEmits
为什么可以直接使用组件,不导入不注册?
- 使用了
unplugin-vue-components
默认src/compoenents
下组件会自动导入注册
- 使用了
cp-nav-bar 组件类型{#cp-nav-bar-type}
解释:给组件添加类型,让写属性和事件可以有提示
提问:
- vant 的组件为啥有提示?
- 看下 vant 的组件类型声明文件
发现:
// 核心代码
// 1. 导入组件实例
import NavBar from './NavBar.vue'
// 2. 声明 vue 类型模块
declare module 'vue' {// 3. 给 vue 添加全局组件类型,interface 和之前的合并interface GlobalComponents {// 4. 定义具体组件类型,typeof 获取到组件实例类型// typeof 作用是得到对应的TS类型VanNavBar: typeof NavBar;}
}
给 cp-nav-bar
组件添加类型
types/components.d.ts
import CpNavBar from '@/components/CpNavBar.vue'declare module 'vue' {interface GlobalComponents {CpNavBar: typeof CpNavBar}
}
验证❓:
- 看看属性提示,事件提示,鼠标放上去有没有类型。
- 代码提示需要组件双闭合
小结:
- 怎么给全局的组件提供类型?
- 写一个类型声明文件,
declare module 'vue'
声明一个 vue 类型模块 - 然后
interface GlobalComponents
书写全局组件的类型 - key组件名称支持大驼峰,value是组件类型,通过 typeof 组件实例得到
- 写一个类型声明文件,
页面布局-头底{#login-html}
准备分析:login页面的基础布局
- 基础布局
vies/Login/index.vue
<script setup lang="ts"></script><template><cp-nav-bar right-text="注册" @click-right="$router.push('/register')"></cp-nav-bar><div class="login"><div class="login-head"><h3>密码登录</h3><a href="javascript:;"><span>短信验证码登录</span><van-icon name="arrow"></van-icon></a></div><!-- == form 表单 == --></div>
</template><style lang="scss" scoped>
.login {padding-top: 46px;&-head {padding: 30px 30px 50px;display: flex;justify-content: space-between;align-items: flex-end;line-height: 1;h3 {font-weight: normal;font-size: 24px;}a {font-size: 15px;}}// .van-form {// padding: 0 14px;// .cp-cell {// height: 52px;// padding: 14px 16px;// box-sizing: border-box;// display: flex;// align-items: center;// .van-checkbox {// a {// color: var(--cp-primary);// padding: 0 5px;// }// }// }// }
}
</style>
页面布局-表单{#login-form}
准备分析:表单的绘制,以及表单根据项目需要进行定制
- 组件结构
Login/index.vue
import { ref } from 'vue'const agree = ref(false)
<div class="login"><!-- ... --><!-- 表单 --><van-form autocomplete="off"><van-field placeholder="请输入手机号" type="tel"></van-field><van-field placeholder="请输入密码" type="password"></van-field><div class="cp-cell"><van-checkbox v-model="agree"><span>我已同意</span><a href="javascript:;">用户协议</a><span>及</span><a href="javascript:;">隐私条款</a></van-checkbox></div><div class="cp-cell"><van-button block round type="primary">登 录</van-button></div><div class="cp-cell"><a href="javascript:;">忘记密码?</a></div></van-form><!-- ... --></div>
.login {// ...// 新增form样式.van-form {padding: 0 14px;.cp-cell {height: 52px;padding: 14px 16px;box-sizing: border-box;display: flex;align-items: center;.van-checkbox {a {color: var(--cp-primary);padding: 0 5px;}}}}
}
图标组件-打包svg地图{#svg-plugin}
实现:把icons目录下svg图片打包为精灵图使用
准备:拷贝02-其它资源中icons目录到项目下
参考文档
- 安装插件
yarn add vite-plugin-svg-icons -D
# or
npm i vite-plugin-svg-icons -D
# or
pnpm install vite-plugin-svg-icons -D
- 使用插件
vite.config.ts
import { VantResolver } from 'unplugin-vue-components/resolvers'
+import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
+import path from 'path'// https://vitejs.dev/config/
export default defineConfig({plugins: [vue(),Components({dts: false,resolvers: [VantResolver({ importStyle: false })]}),
+ createSvgIconsPlugin({
+ // 指定图标文件夹,绝对路径(NODE代码)
+ iconDirs: [path.resolve(process.cwd(), 'src/icons')]
+ })],
- 导入到main
import router from './router'
// 注册图标
+import 'virtual:svg-icons-register'
- 使用svg精灵地图
<svg aria-hidden="true"><!-- #icon-文件夹名称-图片名称 --><use href="#icon-login-eye-off" /></svg>
小结:
icons文件打包的产物?
- 会生成一个 svg 结构(js创建的)包含所有图标,理解为
精灵图
- 会生成一个 svg 结构(js创建的)包含所有图标,理解为
怎么使用svg图标?
- 通过 svg 标签
#icon-文件夹名称-图片名称
指定图片,理解精灵图定位坐标
- 通过 svg 标签
图标组件-封装svg组件{#svg-com}
实现:把 svg 标签使用组件封装起来,完成密码可见切换功能。
- 组件
components/CpIcon.vue
<script setup lang="ts">
// 提供name属性即可
defineProps<{name: string
}>()
</script><template><svg aria-hidden="true" class="cp-icon"><use :href="`#icon-${name}`" /></svg>
</template><style lang="scss" scoped>
.cp-icon {// 和字体一样大width: 1em;height: 1em;
}
</style>
- 类型
types/components.d.ts
import CpNavBar from '@/components/CpNavBar.vue'
+ import CpIcon from '@/components/CpIcon.vue'declare module 'vue' {interface GlobalComponents {CpNavBar: typeof CpNavBar
+ CpIcon: typeof CpIcon}
}
提示:
- 有些图标可以根据 style 中
color
的值来设置颜色,图标是否有这个功能取决于 UI 做图片时否开启。
实现切换密码可见功能:Login/index.vue
// 表单数据
const mobile = ref('')
const password = ref('')
// 控制密码是否显示
const show = ref(false)
<van-field v-model="mobile" placeholder="请输入手机号" type="tel"></van-field>
<van-field v-model="password" placeholder="请输入密码" :type="show ? 'text' : 'password'"><template #button><cp-icon @click="show = !show" :name="`login-eye-${show ? 'on' : 'off'}`"></cp-icon></template>
</van-field>
小结:
- 表单绑定数据后,通过 show 切换 text 和 password,对应切换图标组件的 name 即可。
表单校验{#login-form-validate}
实现:单个表单项校验,以及整体表单校验
- 提取表单校验规则(为了其他页面复用)
utils/rules.ts
// 表单校验
const mobileRules = [{ required: true, message: '请输入手机号' },{ pattern: /^1[3-9]\d{9}$/, message: '手机号格式不正确' }
]const passwordRules = [{ required: true, message: '请输入密码' },{ pattern: /^\w{8,24}$/, message: '密码需8-24个字符' }
]export { mobileRules, passwordRules }
- 单个表单项校验
Login/index.vue
import { mobileRules, passwordRules } from '@/utils/rules'
<van-fieldv-model="mobile"
+ :rules="mobileRules"placeholder="请输入手机号" type="tel"></van-field><van-fieldv-model="password"
+ :rules="passwordRules"placeholder="请输入密码":type="show ? 'text' : 'password'">
- 以及整体表单校验
Login/index.vue
设置button组件为原生 submit 类型按钮
<van-button
block round
type="primary"
+ native-type="submit"
>登 录
</van-button>
监听表单校验成功后 submit 事件
<van-formautocomplete="off"
+ @submit="login">
import { Toast } from 'vant'// 表单提交
const login = () => {if (!agree.value) return Toast('请勾选我已同意')// 验证完毕,进行登录
}
小结:
- 怎么给单个表单加校验?
- rules 属性,规则和 element-ui 类似
- 怎么给整个表单加校验?
- 按钮组件设置
native-type="submit"
,表单组件绑定@submit
事件
- 按钮组件设置
密码登录{#login-logic}
实现:通过手机号和密码进行登录
:::warning 温馨提示
- 提供了100个测试账号
- 手机号:13230000001 - 13230000100
- 密码:abc12345
:::
登录逻辑:
- 定义一个 api 接口函数
- 登录成功:
- 存储用户信息
- 回跳页面,或者进入个人中心
- 提示
落地代码:
- api函数
api/user.ts
import type { User } from '@/types/user'
import { request } from '@/utils/request'// 密码登录
export const loginByPassword = (mobile: string, password: string) =>request.post<User>('/login/password', { mobile, password })
- 进行登录
Login/index.vue
import { loginByPassword } from '@/api/user'
import { useUserStore } from '@/stores'
import { useRoute, useRouter } from 'vue-router'
const store = useUserStore()
const router = useRouter()
const route = useRoute()
// 表单提交
const login = async () => {if (!agree.value) return Toast('请勾选我已同意')// 验证完毕,进行登录const res = await loginByPassword(mobile.value, password.value)store.setUser(res.data)// 如果有回跳地址就进行回跳,没有跳转到个人中心router.push((route.query.returnUrl as string) || '/user')Toast.success('登录成功')
}
说明❓:Toast消息提示需要单独添加样式
main.ts
...
+ import 'vant/es/toast/style';
短信登录-切换效果(课堂练习){#code-toggle}
实现:添加短信登录与密码登录界面切换,添加code的校验
步骤:
- 完成界面切换
- 完成code校验
需求分析❓:
- 定义切换密码和短信登录响应变量isPass:true 密码登录 | false 短信登录
- 使用响应变量做标题和表单项条件渲染
- 为验证码code添加响应变量和rules校验规则
代码:
1)完成界面切换 Login/index.vue
- 切换数据
const isPass = ref(true)
- 标题切换
<div class="login-head"><h3>{{ isPass ? '密码登录' : '短信验证码登录' }}</h3><a href="javascript:;" @click="isPass = !isPass"><span>{{ !isPass ? '密码登录' : '短信验证码登录' }}</span><van-icon name="arrow"></van-icon></a></div>
- 表单项切换
<van-field
+ v-if="isPass"v-model="password":rules="passwordRules"placeholder="请输入密码":type="show ? 'text' : 'password'"><template #button><cp-icon @click="show = !show" :name="`login-eye-${show ? 'on' : 'off'}`"></cp-icon></template></van-field>
+ <van-field v-else placeholder="短信验证码"><template #button><span>发送验证码</span></template>
+ </van-field>
2)完成code校验
- 校验规则
utils/rules.ts
const codeRules = [{ required: true, message: '请输入验证码' },{ pattern: /^\d{6}$/, message: '验证码6个数字' }
]export { mobileRules, passwordRules, codeRules }
- 使用规则
Login/index.vue
import { codeRules } from '@/utils/rules'
const code = ref('')
<van-field v-else v-model="code" :rules="codeRules" placeholder="短信验证码">
小结:
- 接下来就是实现
发送短信
和合并短信登录
的功能了
短信登录-发送短信(课堂练习){#code-send}
实现:点击按钮发送验证码功能
步骤:
- API 接口函数
- 发送验证码逻辑
- 倒计时逻辑
需求分析❓:
定义发送验证码api需要的ts联合类型:‘login’ 登录 | ‘register’ 注册
封装发送验证码api接口方法
发送按钮绑定点击事件,发送验证码,满足两个条件:
- 定义倒计时变量time,默认值0=》大于0说明已经发送,60s内不能再次发送
- 获取form 组件实例,使用实例validate方法校验,每次输入的手机号格式是否正确
调用发送验证码api接口
验证码发送成功后,设置time倒计时60s,使用定时器开启倒计时,结束关闭定时器
组件卸载时,清除定时器(倒计时没有结束,就登录跳转页面情况)
代码:
1)API 接口函数
- 类型
types/user.d.ts
// 短信验证码类型
export type CodeType = 'login' | 'register'
- 接口
api/user.ts
+ import type { CodeType, User } from '@/types/user'
import { request } from '@/utils/request'// 密码登录
export const loginByPassword = (mobile: string, password: string) =>request.post<User>('/login/password', { mobile, password })+ // 发送验证码
+ export const sendMobileCode = (mobile: string, type: CodeType) =>request.get('/code', { params: { mobile, type } })
2)发送验证码逻辑
- 校验没在倒计时
<span @click="send">发送验证码</span>
const time = ref(0)
const send = async () => {// 已经倒计时time的值大于0,60s内不能重复发送验证码if (time.value > 0) return
}
- 校验手机表单项
使用 form 组件的函数 参考文档
<van-fieldv-model="mobile"
+ name="mobile":rules="mobileRules"placeholder="请输入手机号"type="tel"></van-field>
import { Toast, type FormInstance } from 'vant'
+const form = ref<FormInstance>()
const time = ref(0)
const send = async () => {if (time.value > 0) return
+ // 验证不通过报错,阻止程序继续执行
+ await form.value?.validate('mobile')
}
- 发送短信验证码
import { sendMobileCode } from '@/api/user'
const send = async () => {if (time.value > 0) returnawait form.value?.validate('mobile')
+ await sendMobileCode(mobile.value, 'login')
+ Toast.success('发送成功')
}
3)倒计时逻辑
- 逻辑代码
const form = ref<FormInstance>()
const time = ref(0)
+let timeId: number
const send = async () => {
if (time.value > 0) returnawait form.value?.validate('mobile')await sendMobileCode(mobile.value, 'login')Toast.success('发送成功')
+ time.value = 60
+ // 倒计时
+ timeId = window.setInterval(() => {
+ time.value--
+ if (time.value <= 0) window.clearInterval(timeId)
+ }, 1000)
}
+onUnmounted(() => {
+ window.clearInterval(timeId)
+})
注意:
组件卸载关闭定时器
定时器相关函数是 window 去调用,因为 node 也有定时器返回类型不一样。
界面展示
<span :class="{ active: time > 0 }" @click="send">{{ time > 0 ? `${time}s后再次发送` : '发送验证码' }}
</span>
短信登录-进行登录(课堂练习){#code-login}
实现:通过短信进行登录
步骤:
- api 接口函数
- 合并到密码登录逻辑中
需求分析❓:
- 封装短信登录api接口方法
- 提交表单登录时,判断是密码还是短信登录,调用对应api接口方法进行登录
代码:
- 接口API
api/user.ts
// 短信登录
export const loginByMobile = (mobile: string, code: string) =>request.post<User>('/login', { mobile, code })
- 合并短信登录
import { loginByMobile } from '@/api/user'
// 表单提交
const login = async () => {if (!agree.value) return Toast('请勾选我已同意')// 验证完毕,进行登录
+ const res = isPass.value
+ ? await loginByPassword(mobile.value, password.value)
+ : await loginByMobile(mobile.value, code.value)store.setUser(res.data)// 如果有回跳地址就进行回跳,没有跳转到个人中心,replace目的 a => login => b 变成 a => brouter.replace((route.query.returnUrl as string) || '/user')Toast.success('登录成功')
}
小结:
- 处理接口和传参不一样,成功后的逻辑都一样的。
2.vue3医疗在线问诊项目 - _登录模块 ==> 代码片段、css变量主题定制、cp-nav-bar组件封装、svg打包精灵图插件、cp-icon组件封装、表单校验、密码登录、短信验证码登录及两者相关推荐
- Abp Core 添加短信验证码登录(动态密码登录)
交流QQ群:555913397 有什么问题可以加群大家一起交流 Abp Core 添加短信验证码登录(动态密码登录) 现目前我国网站的已经很少使用电子邮箱了,基本上都是手机号作为账号,有时候粗心的用户 ...
- security模仿密码登录实现短信验证码登录
security模仿密码登录实现短信验证码登录 模仿UsernamePasswordAuthenticationToken创建短信验证码的token类SmsAuthenticationToken /* ...
- 5.Spring Security 短信验证码登录
Spring Security 短信验证码登录 在 Spring Security 添加图形验证码一节中,我们已经实现了基于 Spring Boot + Spring Security 的账号密码登录 ...
- java antd实现登录,基于 antd pro 的短信验证码登录
概要 整体流程 前端 页面代码 请求验证码和登录的 service (src/services/login.js) 处理登录的 model (src/models/login.js) 后端 短信验证码 ...
- OAuth2.0 - 自定义模式授权 - 短信验证码登录
一.OAuth2.0 - 自定义模式授权 上篇文章我们分析了目前的情况,演示了微服务的大环境下在保证安全的情况下通过SpringGateWay实现统一的鉴权处理,但是前面的演示中,我们都是基于用户名密 ...
- SpringBoot OAuth2.0 使用短信验证码登录授权
SpringBoot OAuth2.0 使用短信验证码登录授权 实现步骤: 自定义授权器,继承 AbstractTokenGranter 类: 重写 getOAuth2Authentication 函 ...
- SpringSecurity短信验证码登录
短信验证码登录 时下另一种非常常见的网站登录方式为手机短信验证码登录,但Spring Security默认只提供了账号密码的登录认证逻辑,所以要实现手机短信验证码登录认证功能,我们需要模仿Spring ...
- 若依RuoYi整合短信验证码登录
背景:若依默认使用账号密码进行登录,但是咱们客户需要增加一个短信登录功能,即在不更改原有账号密码登录的基础上,整合短信验证码登录. 一.自定义短信登录 token 验证 仿照 UsernamePass ...
- Redis(2)短信验证码登录
Redis实现短信验证码登录 登录流程 1.发送验证码: 2.短信验证码登录,注册 3.校验登录状态 解决状态登录刷新问题 redis指令参考:https://blog.csdn.net/weixin ...
最新文章
- 数据恢复专业基础之python解释NTFS runlist的代码
- SAP 电商云 Spartacus 5_0.md 迁移文档的编写格式
- bootstrap获取弹框数据_Bootstrap模态弹出框的实例教程
- 如何应对缓存穿透和缓存雪崩问题?极其重要
- POJ2246 HDU1082 ZOJ1094 UVA442 Matrix Chain Multiplication题解
- (转)switch与ifelse的效率问题 .
- 历年软件设计师 试卷 参考案例解析
- (转)国内外三个不同领域巨头分享的Redis实战经验及使用场景
- warning: TCG doesn‘t support requested feature: CPUID.01H:ECX.vmx [bit 5]
- B-spline算法(B样条曲线)
- 关于彭先生和我的未来呀~
- 西瓜视频直播助手下载与安装过程 0523
- GB18030全汉字表
- 四川省眉山市2021年高考成绩查询,四川眉山中学2021年排名
- 苏宁大数据怎么运营_苏宁的数据超市带你认识大数据这个营销利器
- CentOS7 搭建 DNS 域名解析服务器
- 操作系统7 文件管理
- 佛祖保佑,永不宕机/永无bug
- App性能测试Case
- h5+vue页面下滑查看更多 页面触底+页面滑动
热门文章
- 《原创lightroom 4中文视频教程【高清包】》(lightroom4 video tutorials)更新至22集[MP4]
- 安装程序检测到计算机重启过程,win10系统安装photoshop提示安装程序检测到计算机重新启动操作可能处于挂起状挂起状态的具体办法...
- Spring.NET - QnA
- php exif信息,php通过exif_read_data函数获取图片的exif信息 PHP
- matlab弧度转角度函数
- Partial convolution Gated convolution
- 以太坊上发送交易的九种办法
- linux系统中如何删除文件中一整列数据
- 仍在王位:经典系统windows xp sp3官方原版下载(附XP序列号)
- C语言停车场模拟管理程序的设计与实现