热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

vue中组件的导出导入_全栈之路:vuecli3项目从搭建优化到docker部署

上一篇,认识Docker全栈之路:前端工程师如何从0开始了解Docker1.创建一个vue项目相信大部分人都已经知道怎么创建项目的,可以跳

上一篇,认识Docker

全栈之路:前端工程师如何从 0 开始了解 Docker

673a689aae054e42ac064f15ce456522.png
1. 创建一个vue项目

相信大部分人都已经知道怎么创建项目的,可以跳过这一节,看下一节。

1.1 安装@vue/cli

# 全局安装 vue-cli脚手架npm install -g @vue/cli

等待安装完成后开始下一步

1.2 初始化项目

vue create vue-cli3-project

  1. 选择一个预设
b14c7890f0b0a5f2b90fab1bed3a494d.png

可以选择默认预设,默认预设包含了babel,eslint我们选择更多功能 Manually select features

回车后来到选择插件

插件选择

这边选择了(Babel、Router、Vuex、Css预处理器、Linter / Formatter 格式检查、Unit测试框架)

路由模式选择

是否使用 history模式的路由 (Yes)

选择一个css预处理器 (Sass/SCSS)

925e5d21bd28286d90342a48fa560de6.png

选择一个eslint配置

这边选择 ESLint + Standard config,个人比较喜欢这个代码规范

0ab98bc787364b61b41b85a9a3af1188.png

选择什么时候进行 eslint 校验

选择(Lint on save)保存是检查

如果你正在使用的vscode编辑器的话,可以配置eslint插件进行代码自动格式化

093f3b279944f872872527174f335977.png

选择测试框架 (Mocha + Chai)

a5674c96d0a06e49585822c586ee0b7a.png

选择将这些配置文件写入到什么地方 (In dedicated config files)

816d040c28767376a2883d763541da3f.png

是否保存这份预设配置?(y)

选是的话,下次创建一个vue项目,可以直接使用这个预设文件,而无需再进行配置。

b40139fef4b3a3d2e6264c5805f3668b.png
2. 全局组件自动注册

在components目录下创建一个global目录,里面放置一些需要全局注册的组件。

index.js作用只要是引入main.vue,导出组件对象

3f09351440f102f5a726f195b71a1090.png

在components中创建一个index.js,用来扫描全局对象并自动注册。

// components/index.jsimport Vue from 'vue'// 自动加载 global 目录下的 .js 结尾的文件const componentsContext = require.context('./global', true, /.js$/)componentsContext.keys().forEach(component => { const componentConfig = componentsContext(component) /** * 兼容 import export 和 require module.export 两种规范 */ const ctrl = componentConfig.default || componentConfig Vue.component(ctrl.name, ctrl)})

最后在入口文件main.js中导入这个index.js中就可以了

3.路由自动引入

在 Vue项目中使用路由,相信想熟的人已经很熟悉怎么使用了,要新增一个页面的话,需要到路由配置中配置该页面的信息。

如果页面越来越多的话,那么如何让我们的路由更简洁呢?

3.1 拆分路由

根据不同的业务模块进行拆分路由

c995c7e859c00c4765297b06cfc30965.png

在每个子模块中导出一个路由配置数组

5648b5fc12a00d98af389a306b74915d.png

在根 index.js中导入所有子模块

34f2957d90d7020d68c6d7696bae40bf.png

3.2 自动扫描子模块路由并导入

当我们的业务越来越庞大,每次新增业务模块的时候,我们都要在路由下面新增一个子路由模块,然后在index.js中导入。

那么如何简化这种操作呢?

通过上面的自动扫描全局组件注册,我们也可以实现自动扫描子模块路由并导入

d12fbd1438f666a2eb866914e51e4a66.png
4. 通过node来生成组件

作为前端开发者,放着 node这么好用的东西如果不能运用起来,岂不是很浪费?

虽然我们通过上面已经实现了组件的自动注册,不过每次新建组件的时候,都要创建一个目录,然后新增一个.vue文件,然后写template、script、style这些东西,然后新建一个index.js、导出vue组件、虽然有插件能实现自动补全,但还是很麻烦有木有。那么我们能不能通过node来帮助我们干这些事情呢?只要告诉node帮我生成的组件名称就行了。其它的事情让node来干

4.1 通过node来生成组件

  • 安装一下chalk,这个插件能让我们的控制台输出语句有各种颜色区分

npm install chalk --save-dev

在根目录中创建一个 scripts 文件夹,

新增一个generateComponent.js文件,放置生成组件的代码、

新增一个template.js文件,放置组件模板的代码

  • template.js

// template.jsmodule.exports = { vueTemplate: compoenntName => { return `

${compoenntName}组件
` }, entryTemplate: `import Main from './main.vue'export default Main`}

generateComponent.js(可以直接查看运行效果)

// generateComponent.js`const chalk = require('chalk')const path = require('path')const fs = require('fs')const resolve = (...file) => path.resolve(__dirname, ...file)const log = message => console.log(chalk.green(`${message}`))const successLog = message => console.log(chalk.blue(`${message}`))const errorLog = error => console.log(chalk.red(`${error}`))const { vueTemplate, entryTemplate } = require('./template')const generateFile = (path, data) => { if (fs.existsSync(path)) { errorLog(`${path}文件已存在`) return } return new Promise((resolve, reject) => { fs.writeFile(path, data, 'utf8', err => { if (err) { errorLog(err.message) reject(err) } else { resolve(true) } }) })}log('请输入要生成的组件名称、如需生成全局组件,请加 global/ 前缀')let componentName = ''process.stdin.on('data', async chunk => { const inputName = String(chunk).trim().toString() /** * 组件目录路径 */ const componentDirectory = resolve('../src/components', inputName) /** * vue组件路径 */ const componentVueName = resolve(componentDirectory, 'main.vue') /** * 入口文件路径 */ const entryComponentName = resolve(componentDirectory, 'index.js') const hasComponentDirectory = fs.existsSync(componentDirectory) if (hasComponentDirectory) { errorLog(`${inputName}组件目录已存在,请重新输入`) return } else { log(`正在生成 component 目录 ${componentDirectory}`) await dotExistDirectoryCreate(componentDirectory) // fs.mkdirSync(componentDirectory); } try { if (inputName.includes('/')) { const inputArr = inputName.split('/') componentName = inputArr[inputArr.length - 1] } else { componentName = inputName } log(`正在生成 vue 文件 ${componentVueName}`) await generateFile(componentVueName, vueTemplate(componentName)) log(`正在生成 entry 文件 ${entryComponentName}`) await generateFile(entryComponentName, entryTemplate) successLog('生成成功') } catch (e) { errorLog(e.message) } process.stdin.emit('end')})process.stdin.on('end', () => { log('exit') process.exit()})function dotExistDirectoryCreate(directory) { return new Promise((resolve) => { mkdirs(directory, function () { resolve(true) }) })}// 递归创建目录function mkdirs(directory, callback) { var exists = fs.existsSync(directory) if (exists) { callback() } else { mkdirs(path.dirname(directory), function () { fs.mkdirSync(directory) callback() }) }}

  • 配置package.json

"new:comp": "node ./scripts/generateComponent"

  • 执行

如果使用 npm 的话 就是

npm run new:comp

如果使用 yarn 的话 就是

yarn new:comp

56ea9eaf0df6eb5a381171a57cf0284b.png

4.2 通过node来生成页面组件

通过上面的逻辑代码我们可以通过node来生成组件了,那么也可以举一反三来生成页面组件。只需稍微修改一下生成组件代码的逻辑。 在scripts目录下新建一个generateView.js文件

// generateView.jsconst chalk = require('chalk')const path = require('path')const fs = require('fs')const resolve = (...file) => path.resolve(__dirname, ...file)const log = message => console.log(chalk.green(`${message}`))const successLog = message => console.log(chalk.blue(`${message}`))const errorLog = error => console.log(chalk.red(`${error}`))const { vueTemplate } = require('./template')const generateFile = (path, data) => { if (fs.existsSync(path)) { errorLog(`${path}文件已存在`) return } return new Promise((resolve, reject) => { fs.writeFile(path, data, 'utf8', err => { if (err) { errorLog(err.message) reject(err) } else { resolve(true) } }) })}log('请输入要生成的页面组件名称、会生成在 views/目录下')let componentName = ''process.stdin.on('data', async chunk => { const inputName = String(chunk).trim().toString() /** * Vue页面组件路径 */ let componentVueName = resolve('../src/views', inputName) // 如果不是以 .vue 结尾的话,自动加上 if (!componentVueName.endsWith('.vue')) { componentVueName += '.vue' } /** * vue组件目录路径 */ const componentDirectory = path.dirname(componentVueName) const hasComponentExists = fs.existsSync(componentVueName) if (hasComponentExists) { errorLog(`${inputName}页面组件已存在,请重新输入`) return } else { log(`正在生成 component 目录 ${componentDirectory}`) await dotExistDirectoryCreate(componentDirectory) } try { if (inputName.includes('/')) { const inputArr = inputName.split('/') componentName = inputArr[inputArr.length - 1] } else { componentName = inputName } log(`正在生成 vue 文件 ${componentVueName}`) await generateFile(componentVueName, vueTemplate(componentName)) successLog('生成成功') } catch (e) { errorLog(e.message) } process.stdin.emit('end')})process.stdin.on('end', () => { log('exit') process.exit()})function dotExistDirectoryCreate(directory) { return new Promise((resolve) => { mkdirs(directory, function () { resolve(true) }) })}// 递归创建目录function mkdirs(directory, callback) { var exists = fs.existsSync(directory) if (exists) { callback() } else { mkdirs(path.dirname(directory), function () { fs.mkdirSync(directory) callback() }) }}

  • 配置package.json 新增一个scripts脚本

"new:view": "node ./scripts/generateView"

  • 执行

如果使用 npm 的话 就是

npm run new:view

如果使用 yarn 的话 就是

yarn new:view

f284b0521a0ad573d7d3d01567d2971d.png

5. axios封装

  • 安装 axios

npm install axios --save// oryarn add axios

5.1 配置不同的环境

在根目录新建三个环境变量文件

9df249f25a0ed514f786aef64ddfaddf.png

分别输入不同的地址, 比如dev就写 dev的api地址、test就写test的api地址

# // .envNODE_ENV = "development"BASE_URL = "https://easy-mock.com/mock/5c4c50b9888ef15de01bec2c/api"

接着在根目录中新建一个 vue.config.js

// vue.config.jsmodule.exports = { chainWebpack: config => { // 这里是对环境的配置,不同环境对应不同的BASE_URL,以便axios的请求地址不同 config.plugin('define').tap(args => { args[0]['process.env'].BASE_URL = JSON.stringify(process.env.BASE_URL) return args }) }}

然后在src目录下新建一个 api文件夹,创建一个 index.js用来配置 axios的配置信息

// src/api/index.jsimport axios from 'axios'import router from '../router'import { Message } from 'element-ui'const service = axios.create({ // 设置超时时间 timeout: 60000, baseURL: process.env.BASE_URL})// post请求的时候,我们需要加上一个请求头,所以可以在这里进行一个默认的设置// 即设置post的请求头为application/x-www-form-urlencoded;charset=UTF-8service.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8''export default service

5.2 请求响应封装

import axios from 'axios'import router from '../router'import { Message } from 'element-ui'const service = axios.create({ // 设置超时时间 timeout: 60000, baseURL: process.env.BASE_URL})/** * 请求前拦截 * 用于处理需要在请求前的操作 */service.interceptors.request.use(config => { const token = localStorage.getItem('token') if (token) { config.headers['Authorization'] = token } return config}, (error) => { return Promise.reject(error)})/** * 请求响应拦截 * 用于处理需要在请求返回后的操作 */service.interceptors.response.use(response => { const responseCode = response.status // 如果返回的状态码为200,说明接口请求成功,可以正常拿到数据 // 否则的话抛出错误 if (responseCode === 200) { return Promise.resolve(response) } else { return Promise.reject(response) }}, error => { // 服务器返回不是 2 开头的情况,会进入这个回调 // 可以根据后端返回的状态码进行不同的操作 const responseCode = error.response.status switch (responseCode) { // 401:未登录 case 401: // 跳转登录页 router.replace({ path: '/login', query: { redirect: router.currentRoute.fullPath } }) break // 403: token过期 case 403: // 弹出错误信息 Message({ type: 'error', message: '登录信息过期,请重新登录' }) // 清除token localStorage.removeItem('token') // 跳转登录页面,并将要浏览的页面fullPath传过去,登录成功后跳转需要访问的页面 setTimeout(() => { router.replace({ path: '/login', query: { redirect: router.currentRoute.fullPath } }) }, 1000) break // 404请求不存在 case 404: Message({ message: '网络请求不存在', type: 'error' }) break // 其他错误,直接抛出错误提示 default: Message({ message: error.response.data.message, type: 'error' }) } return Promise.reject(error)})export default service

Message 方法是 element-ui 提供的一个消息提示组件、大家可以根据自己的消息提示组件进行替换

5.3 断网处理

在响应拦截中添加处理逻辑

service.interceptors.response.use(response => { const responseCode = response.status // 如果返回的状态码为200,说明接口请求成功,可以正常拿到数据 // 否则的话抛出错误 if (responseCode === 200) { return Promise.resolve(response.data) } else { return Promise.reject(response) }}, error => { // 断网 或者 请求超时 状态 if (!error.response) { // 请求超时状态 if (error.message.includes('timeout')) { console.log('超时了') Message.error('请求超时,请检查网络是否连接正常') } else { // 可以展示断网组件 console.log('断网了') Message.error('请求失败,请检查网络是否已连接') } return } // 省略其它代码 ······ return Promise.reject(error)})

5.4 封装图片上传

// src/api/index.jsexport const uploadFile = formData => { const res = service.request({ method: 'post', url: '/upload', data: formData, headers: { 'Content-Type': 'multipart/form-data' } }) return res}

调用

async uploadFile (e) { const file = document.getElementById('file').files[0] const formdata = new FormData() formdata.append('file', file) await uploadFile(formdata)}

5.5 请求 显示 Loading 效果

let loading = nullservice.interceptors.request.use(config => { // 在请求先展示加载框 loading = Loading.service({ text: '正在加载中......' }) // 省略其它代码 ······ return config}, (error) => { return Promise.reject(error)})service.interceptors.response.use(response => { // 请求响应后关闭加载框 if (loading) { loading.close() } // 省略其它代码 ······}, error => { // 请求响应后关闭加载框 if (loading) { loading.close() } // 省略其它代码 ······ return Promise.reject(error)})

6. 巧用 Mixins

6.1 封装 store 公用方法

假设有这样一个场景,我们通过 vuex 封装了获取新闻列表的 function

import Vue from 'vue'import Vuex from 'vuex'import { getNewsList } from '../api/news'Vue.use(Vuex)const types = { NEWS_LIST: 'NEWS_LIST'}export default new Vuex.Store({ state: { [types.NEWS_LIST]: [] }, mutations: { [types.NEWS_LIST]: (state, res) => { state[types.NEWS_LIST] = res } }, actions: { [types.NEWS_LIST]: async ({ commit }, params) => { const res = await getNewsList(params) return commit(types.NEWS_LIST, res) } }, getters: { getNewsResponse (state) { return state[types.NEWS_LIST] } }})

然后在新闻列表页,我们通过 mapAction、mapGetters来调用Action和getters 我们需要写上这些代码

import { mapActions, mapGetters } from 'vuex'computed: { ...mapGetters(['getNewsResponse'])},methods: { ...mapActions(['NEWS_LIST'])}

在假设,在另一个页面又需要重新调用获取新闻列表的接口,我们又要在写一遍上面的代码对吧?

复制粘贴就是干有木有?

如果接口突然加了一个参数,那岂不是每个要用到这个接口的代码都得加这个参数。

复制粘贴一时爽,需求一改你就爽

既然是重复的代码,我们肯定要复用,这时候Vue提供的Mixin就起了大作用了

  • 封装 news-mixin.js 在 src下创建一个mixins目录,用来管理所有的mixins 新建一个news-mixin.js

import { mapActions, mapGetters } from 'vuex'export default { computed: { ...mapGetters(['getNewsResponse']) }, methods: { ...mapActions(['NEWS_LIST']) }}

然后在需要用到的组件中引入这个mixin,就能直接调用这个方法了。不管多少个页面,只要引入这个mixin,直接就能使用。

需求一改的话,也只需要修改这个mixin文件

// news/index.vueimport Vue from 'vue'import newsMixin from '@/mixins/news-mixin'export default { name: 'news', mixins: [newsMixin], data () { return {} }, async created () { await this.NEWS_LIST() console.log(this.getNewsResponse) }}

6.2 扩展

除了封装 vuex 的公用方法,其实还有很多的东西也能做封装。例如:分页对象,表格数据,公用方法、等等就不一一举例了。可以看github

在多个地方经常使用,就可以考虑封装成mixin,不过请写好注释哦。不然就会有人在背后骂你了!!你懂的~~

7. 优化

7.1 gzip压缩

  • 安装compression-webpack-plugin插件

npm install compression-webpack-plugin --save-dev// oryarn add compression-webpack-plugin --dev

  • 在 vue.config.js 中添加配置

// vue.config.jsconst CompressionPlugin = require('compression-webpack-plugin')module.exports = { chainWebpack: config => { // 这里是对环境的配置,不同环境对应不同的BASE_URL,以便axios的请求地址不同 config.plugin('define').tap(args => { args[0]['process.env'].BASE_URL = JSON.stringify(process.env.BASE_URL) return args }) if (process.env.NODE_ENV === 'production') { // #region 启用GZip压缩 config .plugin('compression') .use(CompressionPlugin, { asset: '[path].gz[query]', algorithm: 'gzip', test: new RegExp('.(' + ['js', 'css'].join('|') + ')$'), threshold: 10240, minRatio: 0.8, cache: true }) .tap(args => { }) // #endregion } }}

npm run build后能看到生成 .gz 文件就OK了。如果你的服务器使用nginx的话,nginx也需要配置开启GZIP、下面会讲到如何在nginx中开启GZIP

396cd5ed7816887f3037904a7713e6d4.png

7.2 第三方库引用cdn

对于 vue、vue-router、vuex、axios和element-ui等等这些不经常改动的库、我们让webpack不对他们进行打包,通过cdn引入,可以减少代码的大小、也可以减少服务器的带宽,更能把这些文件缓存到客户端,客户端加载的会更快。

  • 配置vue.config.js

const CompressionPlugin = require('compression-webpack-plugin')module.exports = { chainWebpack: config => { // 省略其它代码 ······ // #region 忽略生成环境打包的文件 var externals = { vue: 'Vue', axios: 'axios', 'element-ui': 'ELEMENT', 'vue-router': 'VueRouter', vuex: 'Vuex' } config.externals(externals) const cdn = { css: [ // element-ui css '//unpkg.com/element-ui/lib/theme-chalk/index.css' ], js: [ // vue '//cdn.staticfile.org/vue/2.5.22/vue.min.js', // vue-router '//cdn.staticfile.org/vue-router/3.0.2/vue-router.min.js', // vuex '//cdn.staticfile.org/vuex/3.1.0/vuex.min.js', // axios '//cdn.staticfile.org/axios/0.19.0-beta.1/axios.min.js', // element-ui js '//unpkg.com/element-ui/lib/index.js' ] } config.plugin('html') .tap(args => { args[0].cdn = cdn return args }) // #endregion } }}

  • 修改index.html

vue-cli3-project We're sorry but vue-cli3-project doesn't work properly without Javascript enabled. Please enable it to continue.

7.3 全站cdn

我们已经把第三方库使用cdn替代了,那么我们build后生成的 js,css之类的文件能否也用cdn呢?

申请自己的cdn域名

要想把自己的资源上传到cdn上,前提是得有自己的cdn域名,如果没有的话,可以到七牛云官网上注册申请一个

  1. 注册七牛云账号
  2. 到七牛云对象存储模块中新建存储空间
  3. 输入存储空间信息
6d849133e8c93e69f12ed40300aa4bd8.png

4、确定创建

5、创建成功后会跳转到这个存储空间的控制台页面

590cf5a521b20298edca706f79a537ce.png

6、其中有个域名就是你的测试域名

7、我们可以在内容管理那上传我们的js、css之类的文件、不过我们的文件那么多,一个一个上传明显不合理。要你你也不干。

这时候,这些批量又重复的操作应该由我们的node出马,让我们来通过 node来批量上传我们的资源文件

将生成的js、css资源上传到七牛cdn

在七牛云官网的文档中心有介绍如何通过node上传文件、感兴趣的人可以自己去研究一下。

  1. 查看AccessKey和SecretKey,在你的个人面板 -> 秘钥管理 ,这两个秘钥待会会用
cad1467edc63042d9931677508efa11d.png
  1. 安装需要的插件

npm install qiniu glob mime --save-dev

  1. 在 scripts目录下创建一个 upcdn.js 文件

// /scripts/upcdn.jsconst qiniu = require('qiniu')const glob = require('glob')const mime = require('mime')const path = require('path')const isWindow = /^win/.test(process.platform)let pre = path.resolve(__dirname, '../dist/') + (isWindow ? '' : '')const files = glob.sync( `${path.join( __dirname, '../dist/**/*.?(js|css|map|png|jpg|svg|woff|woff2|ttf|eot)' )}`)pre = pre.replace(//g, '/')const options = { scope: 'source' // 空间对象名称 }var config = { qiniu: { accessKey: '', // 个人中心 秘钥管理里的 AccessKey secretKey: '', // 个人中心 秘钥管理里的 SecretKey bucket: options.scope, domain: 'http://ply4cszel.bkt.clouddn.com' }}var accessKey = config.qiniu.accessKeyvar secretKey = config.qiniu.secretKeyvar mac = new qiniu.auth.digest.Mac(accessKey, secretKey)var putPolicy = new qiniu.rs.PutPolicy(options)var uploadToken = putPolicy.uploadToken(mac)var cf = new qiniu.conf.Config({ zone: qiniu.zone.Zone_z2})var formUploader = new qiniu.form_up.FormUploader(cf)async function uploadFileCDN (files) { files.map(async file => { const key = getFileKey(pre, file) try { await uploadFIle(key, file) console.log(`上传成功 key: ${key}`) } catch (err) { console.log('error', err) } })}async function uploadFIle (key, localFile) { const extname = path.extname(localFile) const mimeName = mime.getType(extname) const putExtra = new qiniu.form_up.PutExtra({ mimeType: mimeName }) return new Promise((resolve, reject) => { formUploader.putFile(uploadToken, key, localFile, putExtra, function ( respErr, respBody, respInfo ) { if (respErr) { reject(respErr) } resolve({ respBody, respInfo }) }) })}function getFileKey (pre, file) { if (file.indexOf(pre) > -1) { const key = file.split(pre)[1] return key.startsWith('/') ? key.substring(1) : key } return file}(async () => { console.time('上传文件到cdn') await uploadFileCDN(files) console.timeEnd('上传文件到cdn')})()

修改 publicPath

修改vue.config.js的配置信息,让其publicPath指向我们cdn的域名

const IS_PROD = process.env.NODE_ENV === 'production'const cdnDomian = 'http://ply4cszel.bkt.clouddn.com'module.exports = { publicPath: IS_PROD ? cdnDomian : '/', // 省略其它代码 ·······}

修改package.json配置

修改package.json配置,使我们build完成后自动上传资源文件到cdn服务器

"build": "vue-cli-service build --mode prod && node ./scripts/upcdn.js



推荐阅读
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • vue使用
    关键词: ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 本文介绍了Python对Excel文件的读取方法,包括模块的安装和使用。通过安装xlrd、xlwt、xlutils、pyExcelerator等模块,可以实现对Excel文件的读取和处理。具体的读取方法包括打开excel文件、抓取所有sheet的名称、定位到指定的表单等。本文提供了两种定位表单的方式,并给出了相应的代码示例。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 安卓select模态框样式改变_微软Office风格的多端(Web、安卓、iOS)组件库——Fabric UI...
    介绍FabricUI是微软开源的一套Office风格的多端组件库,共有三套针对性的组件,分别适用于web、android以及iOS,Fab ... [详细]
  • 本文介绍了在Linux下安装Perl的步骤,并提供了一个简单的Perl程序示例。同时,还展示了运行该程序的结果。 ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • 高质量SQL书写的30条建议
    本文提供了30条关于优化SQL的建议,包括避免使用select *,使用具体字段,以及使用limit 1等。这些建议是基于实际开发经验总结出来的,旨在帮助读者优化SQL查询。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • ubuntu用sqoop将数据从hive导入mysql时,命令: ... [详细]
  • 浏览器中的异常检测算法及其在深度学习中的应用
    本文介绍了在浏览器中进行异常检测的算法,包括统计学方法和机器学习方法,并探讨了异常检测在深度学习中的应用。异常检测在金融领域的信用卡欺诈、企业安全领域的非法入侵、IT运维中的设备维护时间点预测等方面具有广泛的应用。通过使用TensorFlow.js进行异常检测,可以实现对单变量和多变量异常的检测。统计学方法通过估计数据的分布概率来计算数据点的异常概率,而机器学习方法则通过训练数据来建立异常检测模型。 ... [详细]
  • Java自带的观察者模式及实现方法详解
    本文介绍了Java自带的观察者模式,包括Observer和Observable对象的定义和使用方法。通过添加观察者和设置内部标志位,当被观察者中的事件发生变化时,通知观察者对象并执行相应的操作。实现观察者模式非常简单,只需继承Observable类和实现Observer接口即可。详情请参考Java官方api文档。 ... [详细]
  • 基于dlib的人脸68特征点提取(眨眼张嘴检测)python版本
    文章目录引言开发环境和库流程设计张嘴和闭眼的检测引言(1)利用Dlib官方训练好的模型“shape_predictor_68_face_landmarks.dat”进行68个点标定 ... [详细]
author-avatar
ccM保佑加琳诺爱儿1984f
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有