使用nuxt

Nuxt.js简单介绍

2016 年 10 月 25 日,zeit.co 背后的团队对外发布了 Next.js,一个 React 的服务端渲染应用框架。几小时后,与 Next.js 异曲同工,一个基于 Vue.js 的服务端渲染应用框架应运而生,我们称之为:Nuxt.js。

Nuxt.js 是一个基于 Vue.js 的通用应用框架。通过对客户端/服务端基础架构的抽象组织,Nuxt.js 主要关注的是应用的 UI渲染。Nuxt.js 预设了利用Vue.js开发服务端渲染的应用所需要的各种配置。

为什么使用Nuxt.js?

  • SSR(服务端渲染)的页面初始加载时间显然优于单页首屏渲染
  • 可以方便的对 SEO 进行管理
  • 无需配置页面路由,内置 vue-rouer,自动依据 pages 目录结构生成对应路由配置
  • 便捷的 HTML 头部标签管理(vue-meta)
  • 项目结构自动代码分层
  • 支持静态化(本文将着重以此展开介绍)

项目创建

为了便于大家快速使用,Nuxt.js 提供了很多模板

starter-template: 基础Nuxt.js模板

typescript-template: 基于Typescript的Nuxt.js模板

express-template: Nuxt.js + Express

koa-template: Nuxt.js + Koa

adonuxt-template: Nuxt.js + AdonisJS

electron-template: Nuxt.js + Electron

等等,更多的可以在这里看到 nuxt-community

这里我们使用 starter-template,可以使用 vue-cli 安装:

$ npm install -g vue-cli
$ vue init nuxt-community/starter-template nuxt-demo
$ cd nuxt-demo
$ npm install

生成项目结构如下:

nuxt-demo/
├── assets/
├── components/
│   └── AppLogo.vue
├── layouts/
│   └── default.vue
├── middleware/
├── pages/
│   └── index.vue
├── plugins/
│   └── README.md
├── static/
│   └── favicon.ico
├── store/
├── nuxt.config.js
├── package.json
└── README.md

可以看出来项目结构还是比较清晰的,接着我们根据业务需求在 vue-cli 脚手架生成的项目基础上扩展和修改出来的目录结构如下(已隐去部分文件):

nuxt-demo/
├── api/                                  //- 接口
│   └── index.js
├── assets/                               //- 需要编译的静态资源,如 scss、less、stylus
│   ├── images/                           //- 图片
│   └── styles/                           //- 样式
├── build/                                //- 自定义的一些编译配置
├── components/                           //- 公用的组件
│   ├── dm-toast.vue                      //- 全局组件`dm-toast`
│   └── ...
├── data/                                 //- 静态数据
├── layouts/                              //- 布局
│   ├── components/
│   │   ├── dm-footer.vue                 //- 公用header
│   │   └── dm-header.vue                 //- 公用footer
│   └── default.vue                       //- 默认布局
├── middleware/                           //- 中间件
├── mixins/                               //- Vue mixins
├── pages/                                //- 页面
│   ├── index.vue                         //- 主页
│   └── ...
├── plugins/                              //- vue插件
│   └── dm-tracker.js/                    //- 挂载utils/tracker.js
├── static/                               //- 无需编译处理的静态资源
│   └── images/                           //- 这里存放了一些通过数据循环出来的图片
├── store/                                //- vuex
│   └── index.js
├── utils/                                //- 工具集
│   ├── index.js
│   ├── http.js                           //- axios
│   ├── tracker.js                        //- PV统计
│   └── tracker-uitl.js
├── vendor/                               //- 第三方的库和插件
│   └── index.js
├── nuxt.config.js                        //- Nuxt.js配置文件
├── seo.config.js                         //- SEO相关配置文件
├── package-lock.json                     //- npm的版本锁
├── package.json
└── README.md

项目配置

Nuxt.js 默认的配置涵盖了大部分使用情形,可通过 nuxt.config.js 来覆盖默认的配置,下面相关配置根据实际项目驱动讲解,未涉及到的配置项可查阅 Nuxt.js 文档。

nuxt.config.js 总览

module.exports = {//- Document Common <head>head: {meta: [title: '我是一个title',{ charset: 'utf-8' },{ name: 'viewport', content: 'width=device-width, initial-scale=1' },{ name: 'renderer', content: 'webkit' },{ name: 'applicable-device', content: 'pc' },{ 'http-equiv': 'X-UA-Compatible', content: 'IE=edge,chrome=1' },{ 'http-equiv': 'Cache-Control', content: 'no-transform' },{ 'http-equiv': 'Cache-Control', content: 'no-siteapp' }],link: [{ rel: 'icon', type: 'image/x-icon', href: '你的icon地址' }],//- 这里可以写一些每个页面需要额外引入的一些js代码,比如:百度统计//- `alert(1)` 仅为代码示例script: [{type: 'text/javascript',innerHTML: `alert(1)`}],//- __dangerouslyDisableSanitizers 设置<script>中的内容不被转义。//- https://github.com/declandewet/vue-meta#__dangerouslydisablesanitizers-string__dangerouslyDisableSanitizers: ['script']}//- 页面切换的时候进度条的颜色loading: { color: '#77b6ff' },//- modules 可以用来扩展核心功能或者添加一些集成//- 这里使用了一个本地开发请求远端接口的反向代理模块 `@nuxtjs/proxy`//- https://nuxtjs.org/api/configuration-modulesmodules: ['@nuxtjs/proxy'],//- 上面 modules 中配置了 '@nuxtjs/proxy' 时,此字段才会生效//- https://github.com/nuxt-community/proxy-moduleproxy: {'/api': 'http://xxx.xxx.com'},//- 在这里注册 `Vue` 的插件、全局组件或者其他的一些需要挂载到 `Vue` 原型下面的东西//- ssr 为 `false` 表示该文件只会在浏览器端被打包引入//- https://nuxtjs.org/api/configuration-pluginsplugins: ['~plugins/dm-toast',{ src: '~plugins/dm-tracker', ssr: false }],//- 配置全局样式文件(每个页面都会被引入)//- `lang` 可以为该样式文件配置相关 loader 进行转译css: ['animate.css',{ src: '~assets/styles/common.scss', lang: 'scss' }],//- 配置 Nuxt.js 应用生成静态站点的具体方式。//- https://nuxtjs.org/api/configuration-generategenerate: {//- 为动态路由添加静态化//- 静态化站点的时候动态路由是无法被感知到的//- 所以可以预测性的在这里配置routes: ['/1','/2','/3'...]},//- router 属性让你可以个性化配置 Nuxt.js 应用的路由(vue-router)//- https://nuxtjs.org/api/configuration-routerrouter: {//- 中间件在每次路由切换前被调用middleware: 'set-env',//- 通过 extendRoutes 来扩展或者修改 Nuxt.js 生成的路由表配置extendRoutes(routes) {}},//- 编译配置build: {//- 使用 webpack-bundle-analyzer 分析并可视化构建后的打包文件//- 你可以基于分析结果来决定如何优化它analyze: true,//- 为客户端和服务端的构建配置进行手动的扩展处理//- https://nuxtjs.org/api/configuration-build#extendextend(config, { isDev, isClient, isServer }) {if (isDev && isClient) {//- 使用 ESLint 保证代码规范config.module.rules.push({enforce: 'pre',test: /\.(js|vue)$/,loader: 'eslint-loader',exclude: /(node_modules)/})}if (!isDev) {config.module.rules //- 覆盖默认 `url-loader` 配置.find((rule) => rule.loader === 'url-loader').options.name = 'images/[name].[ext]?v=[hash:7]'}},//- 这里可以自定义打包后的文件名//- `hash` 项目中任何一个文件改动后就会被重新创建//- `chunkhash` 是根据模块内容计算出的hash值,对应的文件发生内容变动就会重新计算//- 生成如下://- <head>//-   ...//-   <link href="//cdn.xxx.com/manifest.js?v=8d09730" rel="preload" as="script">//-   <link href="//cdn.xxx.com/vendor.js?v=8d09730" rel="preload" as="script">//-   <link href="//cdn.xxx.com/app.js?v=fea3ec0" rel="preload" as="script">//-   <link href="//cdn.xxx.com/pages_index.js?v=6f7b904" rel="preload" as="script">//-   ...//- </head>filenames: {manifest: 'js/manifest.js?v=[hash:7]',vendor: 'js/vendor.js?v=[hash:7]',app: 'js/app.js?v=[chunkhash:7]',//- `chunk` 这里这样使用编译会报错,最后面会讲解相关解决方案chunk: 'js/[name].js?v=[chunkhash:7]'},//- 自定义 postcss 配置//- https://nuxtjs.org/api/configuration-build#postcsspostcss: [require('autoprefixer')({browsers: ['> 1%', 'last 3 versions', 'not ie <= 8']})],//- 这里可以设置你的CDN地址,生成的静态资源将会基于此CDN地址加上URL前缀publicPath: '//cdn.xxx.com/',//- Nuxt.js 允许你在生成的 vendor.js 文件中添加一些模块,以减少应用 bundle 的体积//- 这里说的是一些你所依赖的第三方模块 (比如 axios),或者使用频率较高的一些自定义模块//- https://nuxtjs.org/api/configuration-build#vendorvendor: ['axios',...]}
}

路由(router)

Nuxt.js 依据 pages 目录结构,自动生成 vue-router 模块的路由配置。

比如:

├── pages/
│   ├── b-case/
│   │   ├── home.vue
│   │   ├── home/
│   │   │   └── _type.vue
│   │   └── _id.vue
│   └── index.vue

生成路由配置如下:

[{name: 'b-case-home',path: '/b-case/home',component: 'E:\\\\nuxt-demo\\\\pages\\\\b-case\\\\home.vue',chunkName: 'pages/b-case/home',children: [{name: 'b-case-home-type',path: ':type?',component: 'E:\\\\nuxt-demo\\\\pages\\\\b-case\\\\home\\\\_type.vue',chunkName: 'pages/b-case/home/_type'}]},{name: 'b-case-id',path: '/b-case/:id?',component: 'E:\\\\nuxt-demo\\\\pages\\\\b-case\\\\_id.vue',chunkName: 'pages/b-case/_id'},{name: 'index',path: '/',component: 'E:\\\\nuxt-demo\\\\pages\\\\index.vue',chunkName: 'pages/index'}
]

如果你想修改已有路由配置可以在 nuxt.config.js 中添加 route.extendRoutes 配置项,覆盖已有路由或者添加新的路由:

module.exports = {...router: {...extendRoutes(routes) {//- `routes` 是一个包含所所有路由配置信息的参数}}
}

Nuxt模块(modules)

如果你对上述路由的配置方式不满意,想要更加个性化的自定义路由,Nuxt.js 社区提供了一款 Nuxt模块 router-module

使用步骤:

首先安装这个模块

npm install @nuxtjs/router --save # OR yarn add @nuxtjs/router

然后在 nuxt.config.js 中添加模块名 到 modules 字段下:

module.exports ={...modules: ['@nuxtjs/router']
}

在项目根目录下创建 routes.js,并 export 一个方法 createRouter。这里有一点要记住,不能使用 pages/ 这个目录,会和 Nuxt.js 官方的路由机制产生冲突。

import Vue from 'vue'
import Router from 'vue-router'
import Home from '../views/home.vue'Vue.use(Router)export function createRouter() {return new Router({mode: 'history',routes: [{path: '/',component: Home}]})
}

其他比较常用的 Nuxt.js 模块:

axios-module:axios模块,它将网络请求与页面的进度条集成

proxy-module:反向代理模块,本地便捷调试远端接口

auth-module:鉴权模块

python-module:用 Python 编写 Nuxt.js 应用程序

pwa-module:把你的站点变成 pwa 渐进式网络应用

配置方法比较类似,这里不作详细讲解

插件(plugins)

插件可以让我们向 Vue 注入一些使用率比较高的属性或者方法,这里我们讲解一个埋点的插件是如何实现的。

在讲解埋点之前我们需要先了解一下PV的概念:PV(page view),即页面浏览量,或点击量,PV之于网站,就像收视率之于电视。

通过 plugins 配置项,我们可以轻而易举的在 Vue 中使用插件。同时我们需要在 plugins 目录下创建对应的文件,以保证配置项可以正确的加载这个文件。

plugins/dm-tracker.js

//- 将发起pv统计的方法挂载到 Vue 原型下
//- 让每个组件都能通过 `this.$tracker` 访问import Vue from 'vue'
import { trackerPlugins } from '../utils/tracker.js'Vue.use(trackerPlugins)

utils/tracker.js 里是一些发起 PV 统计所调用的代码(隐去了部分业务代码)。

utils/tracker.js

.../*** 发起PV统计* @param {String} caFrom - ev: @ca_from* @param {Object} vueRouteName - vm.$route.name* @return {Promise} 成功`then`或者失败`catch`的回调*/
const tracker = (caFrom, vueRouteName) => {...
}export default trackerexport const trackerPlugins = {install(Vue, options) {Vue.prototype.$tracker = tracker}
}

我们发现几乎每次初始化进入或者跳转到一个新的页面都需要调用 this.$tracker 这个方法,要是在每个页面文件里加岂不是很麻烦,况且如果将埋点深入到业务层后期维护更新不免产生一些不必要的繁琐,所以我们在 layout/default.vue 里面对 $route 进行监听,同时设置 watch 参数 immediate: true,便可针对每个页面实现这个功能。

layout/default.vue

...mounted() {//- 通过监听路由变化,得到不同页面的 pv 统计参数,同时 `immediate: true` 使得每次页面初始进来也会默认执行一次this.$watch('$route', ({ name }) => this.$tracker('-', name), { immediate: true })}
...

至此,就完成了一个 PV 统计插件。

页面元信息(head)

Nuxt.js 文档是这么说的:
使用 head 方法可以设置当前页面的头部标签,在 head 方法里可通过 this 关键字来获取组件的数据,所以你可以利用页面组件的数据来个性化设置 meta 标签。为了避免子组件中的 meta 标签不能正确覆盖父组件中相同的标签而产生重复的现象,建议利用 hid 键为 meta 标签配一个唯一的标识编号。请阅读关于 vue-meta 的更多信息。

官方示例:

<template><h1>{{ title }}</h1>
</template><script>
export default {data () {return {title: 'Hello World!'}},head () {return {title: this.title,meta: [{ hid: 'description', name: 'description', content: 'My custom description' }]}}
}
</script>

根据官方文档的描述,我们了解到页面里的 head 配置优先级高于 nuxt.config.js 中的 head,就是说同等的配置会覆盖 nuxt.config.js 中的 head 相关位置的配置。但是这个等同覆盖的条件是你为它设置了同一个 hid,它会以此作为等同替换的条件去查找相关 dom 元素进行替换。

因为项目生成的是多页面静态站点,很多页面需要配置的 meta 多少有些不一样,深入到每一个页面去写单独的配置信息不免繁琐了许多,所以我们可以在 nuxt.config.jshead 字段中将公用的一些 head 信息放在里面;所以我们是不是可以把它单独抽离出来作为一个配置文件,并和每个页面的路由名字($route.name)关联起来,这样按照理想格式的 seo.config.js 就诞生了。

seo的配置文件写好了,接下来我们应该怎么才能注入这个配置呢,很简单,只需要在 default.vuehead 字段下将不同页面的配置,将他们关联起来。这样就达到了通过每个页面的路由名字($route.name)来映射和渲染对应的 meta。

layout/default.vue

<template><div><dm-header/><nuxt/><dm-footer/></div>
</template><script>
import DmHeader from './components/dm-header'
import DmFooter from './components/dm-footer'const heads = seo => function getHeadsMap() {const map = {}for (const key in seo) {map[key] = seo[key].head}return map
}const routeMapHead = heads(require('../seo.config'))export default {components: { DmHeader, DmFooter },computed: { routeMapHead },head() {//- SEO 的中心化管理, 根据路由 `$route.name` 映射 Document  <head>const route = this.$routeconst head = this.routeMapHead[route.name]return typeof head === 'function' ? head(route) : head}
}
</script>

seo.config.js

//- 根据路由 `$route.name` 映射配置
//- path - 页面的访问路径
//- head - Document <head>,页面的元信息
module.exports = {'index': {head: {title: '我是首页',meta: [{ hid: 'keywords', name: 'keywords', content: '' },{ hid: 'description', name: 'description', content: '' },{ name: 'mobile-agent', content: 'format=wml; url=//该页面对应的移动端网址/' },{ name: 'mobile-agent', content: 'format=xhtml; url=//该页面对应的移动端网址/' },{ name: 'mobile-agent', content: 'format=html5; url=//该页面对应的移动端网址/' }],link: [{ rel: 'alternate', type: 'applicationnd.wap.xhtml+xml', media: 'handheld', href: '//该页面对应的移动端网址/' }]}},//- head 可以是一个 `function`//- `function` 中会接收过来一个参数 `route`,表示当前页面的路由信息//- 可以根据这个做一些动态的配置信息//- 比如动态路由生成的页面中的 meta 信息,可能会根据页面内容来决定'name': {head(route) {const titles = {'1': 'ofo小黄车','2': '盒马生鲜','3': '顺丰速运'}return {title: `${titles[route.params.id]}_客户案例-斗米网`,meta: [{ name: 'mobile-agent', content: `format=wml; url=//该页面对应的移动端网址${route.fullPath}` },{ name: 'mobile-agent', content: `format=xhtml; url=//该页面对应的移动端网址${route.fullPath}` },{ name: 'mobile-agent', content: `format=html5; url=//该页面对应的移动端网址${route.fullPath}` }],link: [{ rel: 'alternate', type: 'applicationnd.wap.xhtml+xml', media: 'handheld', href: `//该页面对应的移动端网址${route.fullPath}` }]}}}...
}

页面布局(layout)

Nuxt.js 中,抽象出来一个新的概念:layout,这样将页面划分为三层:1. layout、2. page、3. component,很方便的在多种布局方案中切换。

+------------------------------+
|            layout            |
|                              |
|   +----------------------+   |
|   |         page         |   |
|   |                      |   |
|   |   +--------------+   |   |
|   |   |  component   |   |   |
|   |   +--------------+   |   |
|   |                      |   |
|   |   +--------------+   |   |
|   |   |  component   |   |   |
|   |   +--------------+   |   |
|   |                      |   |
|   |   +--------------+   |   |
|   |   |  component   |   |   |
|   |   +--------------+   |   |
|   +----------------------+   |
|                              |
+------------------------------+

在页面 pages/*.vue 文件中可以指定一种布局,不指定的时候会使用默认布局 default

比如以下目录结构:

├── layouts/                              //- 布局
│   ├── components/
│   │   ├── dm-footer.vue                 //- 公用header
│   │   └── dm-header.vue                 //- 公用footer
│   ├── box.vue
│   └── default.vue                       //- 默认布局
├── pages/                                //- 页面
│   └── index.vue

使用 box.vue 的布局,<nuxt/> 对应页面部分,类似 Vue 的 slot

layouts/box.vue

<template><div><dm-header/><nuxt/><dm-footer/></div>
</template><script>
import DmHeader from './components/dm-header'
import DmFooter from './components/dm-footer'export default {components: { DmHeader, DmFooter }
}
</script>

pages/index.vue

<script>
export default {layout: 'box'...
}
</script>

状态管理(vuex)

像普通的 Vue 应用一样,在 Nuxt.js 中也可以使用 vuex,而且无需额外 npm install vuex --save 和配置,只要直接在项目根目录创建 store 文件夹,Nuxt.js 会自动去寻找下面的 .js 文件,并自动进行状态树的模块划分。

Nuxt.js 支持两种使用 store 的方式:

普通方式:返回一个 Vuex.Store 实例,感觉很眼熟有木有

store/index.js

import Vue from 'vue'
import Vuex from 'vuex'Vue.use(Vuex)const store = () => new Vuex.Store({state: {counter: 0},mutations: {increment (state) {state.counter++}}
})export default store

模块方式:store 目录下的每个 .js 文件会被转换成为状态树指定命名的子模块,index.js 会被作为根模块

store/index.js

export const state = () => ({counter: 0
})export const mutations = {increment (state) {state.counter++}
}

store/todos.js

export const state = () => ({list: []
})export const mutations = {toggle (state, todo) {todo.done = !todo.done}
}

最终渲染出来的状态树:

new Vuex.Store({state: { counter: 0 },mutations: {increment (state) {state.counter++}},modules: {todos: {state: {list: []},mutations: {toggle (state, { todo }) {todo.done = !todo.done}}}}
})

一键静态化

npm run generate

然后会在项目根目录生成 dist 目录,静态化后的资源都在其内(html、js、css…)

当然,在静态化的时候还是遇到了一些问题:我们有一个专门放置静态资源的 CDN 分发服务器,所以每次版本更新的时候需要版本智能更新(不然用户访问到的可能就是旧的资源),即对应的模块内容发生改变时才去更新这个版本号,虽然可以通过 js/[name].[chunkhash:7].js这样的配置实现,但是 CDN 访问到的静态资源是通过 git 控制上线的,所以这样生成的静态资源,文件名每次可能不一样,这样就会越来越多,git 需要定时清理,比较麻烦。于是才有了这样一个两全的方案:既控制了版本更新,也让文件名不产生变动。

就是如下配置:

module.exports = {...build: {...filenames: {...chunk: 'js/[name].js?v=[chunkhash:7]'}}
}

想法很丰满,现实很骨感,在 nuxt.config.js 中使用这样的配置静态化编译的时候会报错 Cannot find module 'pages_index.js?v=6f7b904...,(⊙o⊙)…经过一系列的源码追踪发现是vue-server-renderer 这个模块的 BUG。

虽然向官方提了相关 issue ,但是因不可抗拒的因素暂时无法修复。

vue-server-renderer/server-plugin.js 78行 asset.name.match(/.js$/) 这个判断里的正则明显把我们设定的格式 js/[name].js?v=[chunkhash:7] 过滤掉了,不会走这个判断,所以我们只要想办法把这个判断条件改一下,让它走这里。发现他同文件上面有个 isJS 函数,这样就省事多了,我们可以直接调用。

所以我们如果改源码的话只需要把这里 asset.name.match(/.js$/) 替换为 isJS(asset.name) 就行了。但是改源码总归不好,因为并不能保证团队其他成员的机器上模块库一致。投机取巧,既然直接修改不好,那就间接修改呗。

开始动手,先安装一个 npm 的模块:

npm install shelljs -D # OR yarn add shelljs -D

接着在项目下新建两个文件:

  • build/nuxt-generate.js:用来执行静态化的一些命令
  • build/vue-server-renderer.patch.js:给 vue-server-renderer 模块打补丁

build/nuxt-generate.js

const shell = require('shelljs')
const { resolve } = require('path')
const nuxt = resolve(__dirname, '../node_modules/.bin/nuxt')
const logProvider = require('consola').withScope('nuxt:generate')shell.exec(`npm run patch`, (code, stdout, stderr) => {if (code !== 0) {logProvider.error(stderr)}//- 上面的命令执行成功之后在执行下面的命令shell.exec(`${nuxt} generate`)
})

build/vue-server-renderer.patch.js

const { resolve } = require('path')
const fs = require('fs')
const SSRJSPath = resolve(__dirname, '../node_modules/vue-server-renderer/server-plugin.js')
const consola = require('consola')
const logProvider = consola.withScope('vue:patch')module.exports = VueSSRPatch()/*** 对 `vue-server-renderer/server-plugin.js` 源码内容进行替换* asset.name.match(/\.js$/)* =>* isJS(asset.name)*/
function VueSSRPatch() {//- 检测该模块是否存在if (fs.existsSync(SSRJSPath)) {let regexp = /asset\.name\.match\(\/\\\.js\$\/\)/let SSRJSContent = fs.readFileSync(SSRJSPath, 'utf8')//- 检测是否存在需要替换的内容(通常是指该项目在本机第一次运行)if (regexp.test(SSRJSContent)) {logProvider.start(`发现vue-server-renderer模块,开始执行修补操作!`)SSRJSContent = SSRJSContent.replace(regexp, 'isJS(asset.name)')fs.writeFileSync(SSRJSPath, SSRJSContent, 'utf8')logProvider.ready(`修补完毕!`)return true}logProvider.warn(`该模块已修补过,无需再次修补,可直接运行\`npm run dev\` 或 \`npm run gen\``)return false}logProvider.warn(`未发现该模块,跳出本次修复!`)return false
}

最后在 package.jsonscripts 添加 genpatch 两条命令:

"scripts": {"dev": "nuxt","generate": "nuxt generate","patch": "node build/vue-server-renderer.patch","gen": "node build/nuxt-generate"
}

patch:本机第一次运行或者更新相关模块(vue-server-renderer)时需要执行一次。

gen
npm run patchnpm run generate 的合并命令,就是说会先后执行这两个,方便本机第一次使用。如果本机执行过 npm run patch可直接 npm run generate,生成相关静态页。

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

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

相关文章

配置HAProxy支持https协议

author&#xff1a;JevonWei版权声明&#xff1a;原创作品 实现http重定向到https HAProxy 创建CA证书 [rootHAProxy ~]# cd /etc/haproxy/ [rootHAProxy haproxy]# mkdir certs [rootHAProxy haproxy]# cd /etc/pki/CA [rootHAProxy CA]# (umask 077;openssl genrsa -out priv…

android 万能倒计时,时分秒倒计时

1、工具类 /*** 作者&#xff1a;created by meixi* 邮箱&#xff1a;15913707499163.com* 日期&#xff1a;2018/12/28 15*/public class TimerUtil {private static final int nHandlerMsg 23566124;private int nStartDelayTime;private int nIntervalTime;private Timer …

菜鸟必备的网络命令

对于菜鸟的我来讲很有保存价值开始菜单中的“运行”是通向程序的快捷途径&#xff0c;输入特定的命令后&#xff0c;即可快速的打开Windows的大部分程序&#xff0c;熟练的运用它&#xff0c;将给我们的操作带来诸多便捷。 winver 检查Windows版本 wmimgmt.msc 打开Windows管理…

实现瀑布流的核心代码

.warp {column-count: 2;column-gap: 10px;padding: 5px; }.item {height: 80px;margin-bottom: 10px;break-inside: avoid; }效果如下

Mac OS X Terminal 101:终端使用初级教程以及Xcode

转自 http://www.renfei.org/blog/mac-os-x-terminal-101.html 最近学习苹果认证的《Mac OS X Support Essentials》教程&#xff0c;看到 Command Line 一节有很多实用的知识&#xff0c;下面选取一部分翻译 笔记&#xff0c;整理成此文。 你可以整天驾驶汽车而不用知道如何修…

android studio 获取SHA1值 MD5值

运行CMD 输入 cd .android 回车 输入 keytool -list -v -keystore D:/yohoo.keystore -storepass android 回车 D:/yohoo.keystore------就是你的keystore的位置 &#xff0c; android------- 就是你的keystore的密码 如果提示keytool 不是内部命令或可运行程序。需先配…

修改远程端口

怎么更改远程桌面3389端口号才能使用服务器更加安全?一些黑客常常利用远程服务器桌面的3389端口进行入侵,因此我们有必要学会如何更改远程桌面的端口号来保护自己. 远程终端服务基于端口3389。入侵者一般先扫描主机开放端口&#xff0c;一旦发现其开放了3389端口&#xff0c;就…

MongoDB 常用运算符

$eq (等于) $gt > (大于) $gte > (大于等于) $lt < (小于) $lte < (小于等于) $ne ! (不等于) $in in (in) $nin !in (not in) 参考&#xff1a;https://docs.mongodb.com/manual/reference/operator/query/ $eq 语法&#xff1a; { <field>: { …

myeclipse使用git图文教程

Git介绍与使用 1、什么是Git Git是分布式版本控制系统 Git是一款免费、开源的分布式版本控制系统&#xff0c;用于敏捷高效地处理任何或小或大的项目。 2、集中式版本控制系统&#xff08;CVS / SVN等&#xff09; 集中式版本控制系统&#xff0c;版本库是集中存放在中央服务器…

汇编64讲(搞免杀、破解必看)

希望大家喜欢!每个课程有1个小时 学完包你会免杀,免的出神入画.....-_-!http://219.144.186.220/hbywjjk/下载地址&#xff08;也可以在线观看&#xff09;mms://221.11.20.228/hbywjjk/1/000.asfmms://221.11.20.228/hbywjjk/2/000.asfmms://221.11.20.228/hbywjjk/3/000.asfm…

centos 安装pm2

npm install -g pm2whereis pm2 pm2: /opt/nodejs/bin/pm2sudo ln -s /opt/nodejs/bin/pm2 /usr/bin/pm2

android Animation 动画。淡出动画

淡出动画 protected void startHotelNearByIconAnim() {AlphaAnimation alphaAnimation new AlphaAnimation(1, 0);//初始化操作&#xff0c;参数传入0和1&#xff0c;即由透明度0变化到透明度为1alphaAnimation.setFillAfter(true);//动画结束后保持状态alphaAnimation.setD…

Java内存模型_基础

线程之间的通信机制有两种&#xff1a; 1、共享内存&#xff1a;线程之间共享程序的公共状态&#xff0c;通过写-读内存中的公共状态进行隐式的通信。 2、消息传递&#xff1a;线程之间没有公共状态&#xff0c;线程之间必须发送消息来显示的进行通信 同步&#xff1a;是指程序…

警惕Oracle DB操作高压线

在日常的数据库技术支持工作中&#xff0c;会发现相当部分的数据库事故和人为操作不当有直接的关系。每次的新员工培训&#xff0c;也会用真实案例来说明和强调正确操作习惯的重要性。在强调职业化&#xff0c;推行可服务性的大环境下&#xff0c;了解数据库操作的高压线&#…

centos 宝塔面板 mongodb 设置用户账号密码登录

挂在网上的mongodb测试数据库&#xff0c;默认的无密码&#xff0c;端口直接登录&#xff0c;本来想着不会有人盯上吧&#xff0c;结果&#xff0c;一个月后&#xff0c;被黑客删库了&#xff0c;所以不管是接口&#xff0c;还是数据库的安全性一定要保证&#xff01;&#xff…