Vue自创插件发布到npm以及使用方法

Vue自创插件发布到npm以及使用方法

目标:创建my-popup-selector下拉框组件,并发布到npm,效果如下图:
在这里插入图片描述
禁用时样式:
在这里插入图片描述

①创建vue项目:

my-popup-selector

②项目目录结构截图如下:

在这里插入图片描述

③在项目根目录新建 packages/ 文件夹用于存放组件,由于 packages/ 是新增的,webpack无法获取编译,因此需要在webpack配置文件里加上相关配置

④在项目根目录新建 vue.config.js 配置文件,并写入一下配置:

module.exports = {
 css: { // 是否将组件中的 CSS 提取至一个独立的 CSS 文件中 (而不是动态注入到 JavaScript 中的 inline 代码)。
   extract: false, // 生产环境下是 true,开发环境下是 false
 },
 // 扩展 webpack 配置,使 packages 加入编译
 // chainWebpack 是一个函数,会接收一个基于 webpack-chain 的 ChainableConfig 实例。允许对内部的 webpack 配置进行更细粒度的修改
 chainWebpack: config => {
   config.module
     .rule('js')
     .include
     .add(__dirname + 'packages') // 注意这里需要绝对路径,所以要拼接__dirname
     .end()
     .use('babel')
     .loader('babel-loader')
     .tap(options => {
       // 修改它的选项...
       return options
     })
 }
}

⑤在 packages/ 文件夹下创建组件,新建 vue-popup-selector/ 文件夹和 index.js 文件,截图如下:
⑥在 my-popup-selector/ 文件加下新建 VueAmazingSelector.vue 组件文件和 index.js 文件,截图如下:

5 - 6步骤图

⑦在 VueAmazingSelector.vue 中编写组件代码:

<template>
  <div class="m-amazing-select" :style="`height: ${height}px;`">
    <div
      :class="['m-select-wrap', {'hover': !disabled, 'focus': showOptions, 'disabled': disabled}]"
      :style="`width: ${width - 2}px; height: ${height - 2}px;`"
      tabindex="0"
      @mouseenter="onInputEnter"
      @mouseleave="onInputLeave"
      @blur="activeBlur && !disabled ? onBlur() : e => e.preventDefault()"
      @click="disabled ? e => e.preventDefault() : openSelect()">
      <div
        :class="['u-select-input', {'placeholder': !selectedName}]"
        :style="`line-height: ${height - 2}px;width: ${width - 37}px; height: ${height - 2}px;`"
        :title="selectedName"
      >{{ selectedName || placeholder }}</div>
      <svg :class="['triangle', {'rotate': showOptions, 'show': !showClose}]" viewBox="64 64 896 896" data-icon="down" aria-hidden="true" focusable="false"><path d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"></path></svg>
      <svg @click.stop="onClear" :class="['close', {'show': showClose}]" focusable="false" data-icon="close-circle" aria-hidden="true" viewBox="64 64 896 896"><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 01-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"></path></svg>
    </div>
    <transition name="fade">
      <div
        v-show="showOptions"
        class="m-options-panel"
        @mouseenter="onEnter"
        @mouseleave="onLeave"
        :style="`top: ${height + 6}px; line-height: ${height - 12}px; max-height: ${ num * (height - 2) }px; width: ${width}px;`">
        <p
          v-for="(option, index) in options" :key="index"
          :class="['u-option', {'option-selected': option[label]===selectedName, 'option-hover': !option.disabled&&option[value]===hoverValue, 'option-disabled': option.disabled }]"
          :title="option[label]"
          @mouseenter="onHover(option[value])"
          @click="option.disabled ? e => e.preventDefault() : onChange(option[value], option[label], index)">
          {{ option[label] }}
        </p>
      </div>
    </transition>
  </div>
</template>
<script>
export default {
  name: 'VueAmazingSelector',
  model: {
    prop: 'selectedValue',
    event: 'model'
  },
  props: {
    options: { // 选项数据
      type: Array,
      default: () => []
    },
    label: { // 选择器字典项的文本字段名
      type: String,
      default: 'label'
    },
    value: { // 选择器字典项的值字段名
      type: String,
      default: 'value'
    },
    placeholder: { // 选择框默认文字
      type: String,
      default: '请选择'
    },
    disabled: { // 是否禁用下拉
      type: Boolean,
      default: false
    },
    allowClear: { // 是否支持清除
      type: Boolean,
      default: false
    },
    width: { // 选择框宽度
      type: Number,
      default: 200
    },
    height: { // 选择框高度
      type: Number,
      default: 36
    },
    num: { // 下拉面板最多能展示的下拉项数,超过后滚动显示
      type: Number,
      default: 6
    },
    selectedValue: { // 当前选中的option条目(v-model)
      type: [Number, String],
      default: null
    }
  },
  data () {
    return {
      selectedName: null,
      hoverValue: null, // 鼠标悬浮项的value值
      activeBlur: true, // 是否激活blur事件
      showClose: false, // 清除按钮显隐
      showOptions: false // options面板
    }
  },
  watch: {
    options () {
      this.initSelector()
      console.log('options')
    },
    selectedValue () {
      this.initSelector()
      console.log('selectedValue')
    }
  },
  mounted () {
    this.initSelector()
  },
  methods: {
    initSelector () {
      if (this.selectedValue) {
        const target = this.options.find(option => option[this.value] === this.selectedValue)
        if (target) {
          this.selectedName = target[this.label]
          this.hoverValue = target[this.value]
        } else {
          this.selectedName = this.selectedValue
          this.hoverValue = null
        }
      } else {
        this.selectedName = null
        this.hoverValue = null
      }
    },
    onBlur () {
      if (this.showOptions) {
        this.showOptions = false
      }
    },
    onInputEnter () {
  // console.log('input enter')
      if (this.allowClear && this.selectedName) {
        this.showClose = true
      }
    },
    onInputLeave () {
      // console.log('input leave')
      if (this.allowClear && this.showClose) {
        this.showClose = false
      }
    },
    onHover (value) {
      this.hoverValue = value
    },
    onEnter () {
      this.activeBlur = false
    },
    onLeave () {
      this.hoverValue = null
      this.activeBlur = true
    },
    openSelect () {
      this.showOptions = !this.showOptions
      if (!this.hoverValue && this.selectedName) {
        const target = this.options.find(option => option[this.label] === this.selectedName)
        this.hoverValue = target ? target[this.value] : null
      }
    },
    onClear () {
      this.showClose = false
      this.selectedName = null
      this.hoverValue = null
    },
    onChange (value, label, index) { // 选中下拉项后的回调
      if (this.selectedValue !== value) {
        this.selectedName = label
        this.hoverValue = value
        this.$emit('model', value)
        this.$emit('change', value, label, index)
      }
      this.showOptions = false
    }
  }
}
</script>
<style lang="less" scoped>
@themeColor: #1890ff; // 自定义主题色
P {
  margin: 0;
}
.m-amazing-select {
  position: relative;
  display: inline-block;
  font-size: 14px;
  font-weight: 400;
  color: rgba(0,0,0,.65);
}
.fade-enter-active, .fade-leave-active {
  transform: scaleY(1);
  transform-origin: 0% 0%;
  opacity: 1;
  transition: all .3s;
}
.fade-enter {
  transform: scaleY(0.8);
  transform-origin: 0% 0%;
  opacity: 0;
}
.fade-leave-to {
  transform: scaleY(1);
  opacity: 0;
}
.m-select-wrap {
  position: relative;
  display: inline-block;
  border: 1px solid #d9d9d9;
  border-radius: 4px;
  cursor: pointer;
  transition: all .3s cubic-bezier(.645,.045,.355,1);
  .u-select-input {
    display: block;
    text-align: left;
    margin-left: 11px;
    margin-right: 24px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .placeholder {
    color: #bfbfbf;
  }
  .triangle {
    position: absolute;
    top: 0;
    bottom: 0;
    margin: auto 0;
    right: 12px;
    width: 12px;
    height: 12px;
    fill: rgba(0,0,0,.25);
    opacity: 0;
    pointer-events: none;
    transition: all 0.3s ease-in-out;
  }
  .rotate {
    transform: rotate(180deg);
    -webkit-transform: rotate(180deg);
  }
  .close {
    opacity: 0;
    pointer-events: none;
    transition: all 0.3s ease-in-out;
    position: absolute;
    top: 0;
    bottom: 0;
    margin: auto 0;
    right: 12px;
    width: 12px;
    height: 12px;
    fill: rgba(140, 140, 140, 0.6);
    &:hover {
      fill: rgba(100, 100, 100,.8);
    }
  }
  .show {
    opacity: 1;
    pointer-events: auto;
  }
}
.hover { // 悬浮时样式
  &:hover {
    border-color: @themeColor;
  }
}
.focus { // 激活时样式
  border-color: @themeColor;
  box-shadow: 0 0 0 2px fade(@themeColor, 20%);
}
.disabled { // 下拉禁用样式
  color: rgba(0,0,0,.25);
  background: #f5f5f5;
  user-select: none;
  cursor: not-allowed;
}
.m-options-panel {
  position: absolute;
  z-index: 999;
  overflow: auto;
  background: #FFF;
  padding: 4px 0;
  border-radius: 4px;
  box-shadow: 0 2px 8px rgba(0,0,0,15%);
  .u-option { // 下拉项默认样式
    text-align: left;
    position: relative;
    display: block;
    padding: 5px 12px;
    font-weight: 400;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    cursor: pointer;
    transition: background .3s ease;
  }
  .option-selected { // 被选中的下拉项样式
    font-weight: 600;
    background: #fafafa;
  }
  .option-hover { // 悬浮时的下拉项样式
    background: #e6f7ff;
    // background: saturate(fade(@themeColor, 12%), 30%);
  }
  .option-disabled { // 禁用某个下拉选项时的样式
    color: rgba(0,0,0,.25);
    user-select: none;
    cursor: not-allowed;
  }
}
</style>

⑧在 my-popup-selector/index.js 中导出组件

// 引入组件
import VueAmazingSelector from './VueAmazingSelector.vue'
 
// 为组件提供 install 安装方法,供按需引入
VueAmazingSelector.install = (Vue) => {
  Vue.component(VueAmazingSelector.name, VueAmazingSelector)
}
 
// 导出组件
export default VueAmazingSelector

⑨在 packages/index.js 文件中对整个组件库进行导出

import VueAmazingSelector from './vue-amazing-selector'
// 存储组件列表
const components = [
  VueAmazingSelector
]
/* 
  定义install 方法,接收Vue作为参数,如果使用use注册插件,则所有的组件都将被注册
*/
const install = function (Vue) {
  // 判断是否安装
  if (install.installed) { return }
  // 遍历所有组件
  components.map(component => {
    Vue.component(component.name, component)
  })
}
// 判断是否引入文件
if (typeof window !== 'undefined' && window.Vue) {
  install(window.Vue)
}
export {
  VueAmazingSelector
}
export default {
  install
}

在 src/main.js 中导入刚创建的组件,检测是否正常可用

import VueAmazingSelector from '../packages'
Vue.use(VueAmazingSelector)
// 在 App.vue 中引用,并启动项目查看

app.vue代码

	<template>
  <VueAmazingSelector
    :options="options"
    label="label"
    value="value"
    placeholder="请选择"
    :disabled="false"
    :width="160"
    :height="36"
    :num="6"
    v-model="selectedValue"
    @change="onChange" />
</template>
<script>
export default {
  name: 'App',
  data () {
    return {
      options: [
        {
          label: '北京市',
          value: 1
        },
        {
          label: '上海市上海市上海市上海市',
          value: 2,
          disabled: true
        },
        {
          label: '郑州市',
          value: 3
        },
        {
          label: '纽约市纽约市纽约市纽约市',
          value: 4
        },
        {
          label: '旧金山',
          value: 5
        },
        {
          label: '悉尼市',
          value: 6
        },
        {
          label: '伦敦市',
          value: 7
        },
        {
          label: '巴黎市',
          value: 8
        }
      ],
      selectedValue: 1
    }
  },
  watch: {
    selectedValue (to) {
      console.log('selectedValue:', to)
    }
  },
  mounted () {
    setTimeout(() => { // 模拟接口调用
      this.selectedValue = 3
    }, 1000)
  },
  methods: {
    onChange (value, label, index) {
      console.log('item:', value, label, index)
    }
  }
}
</script>

⑪在 package.json 的 scripts 中添加一条编译命令


--target: 构建目标,默认为应用模式。这里修改为 lib 启用库模式。
--dest : 输出目录,默认 dist。这里我们改成 lib
[entry]: 最后一个参数为入口文件,默认为 src/App.vue。这里我们指定编译 packages/ 组件库目录。
 
"scripts": {
	"lib": "vue-cli-service build --target lib --name selector --dest lib packages/index.js"
}

⑫执行编译命令

yarn lib(或num run lib)

执行结果如下图:

在这里插入图片描述

然后在项目根目录会生成如下图所示文件夹:

在这里插入图片描述

⑬在终端执行 npm init 初始化包配置文件package.json 可忽略这一步

package.json部分截图如下:

在这里插入图片描述
name: 包名,该名字是唯一的。可在 npm 官网搜索名字,不可重复。
version: 版本号,每次发布至 npm 需要修改版本号,不能和历史版本号相同。
main: 入口文件,需指向最终编译后的包文件。
author:作者

private:是否私有,需要修改为 false 才能发布到 npm

⑭在项目根目录创建 .npmignore 文件,设置忽略发布的文件,类似 .gitignore 文件

只有编译后的 lib 目录、package.json、README.md是需要被发布的

# 忽略目录

.DS_Store

node_modules

packages/

public/

src/

# 忽略指定文件

.eslintrc.cjs

.gitignore

.npmignore

.npmrc

babel.config.js

vue.config.js

yarn.lock

*.map

⑮编写README.md文件(使用markdown格式)

参考文档: http://markdown.p2hp.com/index.html
# vue-amazing-selector
 
## An Amazing Select Component For Vue2
 
## Install & Use
 
```sh
npm install vue-amazing-selector
#or
yarn add vue-amazing-selector

Import and register component

Global

import Vue from 'vue'
import VueAmazingSelector from 'vue-amazing-selector'
Vue.use(VueAmazingSelector)

Local

<template>
  <VueAmazingSelector
    :options="options"
    label="label"
    value="value"
    placeholder="请选择"
    :disabled="false"
    :width="160"
    :height="36"
    :num="6"
    v-model="selectedValue"
    @change="onChange" />
</template>
<script>
export default {
  name: 'App',
  data () {
    return {
      options: [
        {
          label: '北京市',
          value: 1
        },
        {
          label: '上海市上海市上海市上海市',
          value: 2,
          disabled: true
        },
        {
          label: '郑州市',
          value: 3
        },
        {
          label: '纽约市纽约市纽约市纽约市',
          value: 4
        },
        {
          label: '旧金山',
          value: 5
        },
        {
          label: '悉尼市',
          value: 6
        },
        {
          label: '伦敦市',
          value: 7
        },
        {
          label: '巴黎市',
          value: 8
        }
      ],
      selectedValue: 1
    }
  },
  watch: {
    selectedValue (to) {
      console.log('selectedValue:', to)
    }
  },
  mounted () {
    setTimeout(() => { // 模拟接口调用
      this.selectedValue = 3
    }, 1000)
  },
  methods: {
    onChange (value, label, index) {
      console.log('item:', value, label, index)
    }
  }
}
</script>
 
## Props
 
| 属性 | 说明 | 类型 | 默认值 |
| :--- | :--- | :--- | :--- |
options | 选项数据 | Array | []
label | 选择器字典项的文本字段名 | String | label
value | 选择器字典项的值字段名 | String | value
placeholder | 选择框默认文字 | String | 请选择
disabled | 是否禁用下拉 | Boolean | false
allowClear | 是否支持清除 | Boolean | false
width | 选择框宽度 | Number | 200
height | 选择框高度 | Number | 36
num | 下拉面板最多能展示的下拉项数,超过后滚动显示 | Number | 6
selectedValue | (v-model)当前选中的option条目 | /Number/String | null
 
## Events
 
事件名 | 说明 | 返回值
:--- | :--- | :---
change | 选择某项下拉后的回调函数 | value, label, index(value值,label文本值,index索引值)

⑯登录npm

如果没有npm账号,可以去npm官网( npm) 注册一个账号

注册成功后在本地查看npm镜像:

npm config get registry

输出:https://registry.npmjs.org 即可

如果不是则需要设置为npm镜像:

npm config set registry https://registry.npmjs.org

然后在终端执行:

npm login

依次输入用户名,密码,邮箱

输出Logged in as…即可

npm whoami // 查看当前用户是否已登录

在这里插入图片描述

⑰发布组件到npm

在终端执行:npm publish

发布成功后即可在npm官网搜索到该组件,如下图;并可以通过 npm install my-popup-selector(或yarn add my-popup-selector)进行安装
在这里插入图片描述

⑱在要使用的项目中安装并注册插件

yarn add my-popup-selector

// 在 main.js 文件中引入并注册:
import Vue from 'vue'
import VueAmazingSelector from 'my-popup-selector'
Vue.use(VueAmazingSelector)

在要使用组件的页面直接使用即可:

<template>
  <VueAmazingSelector
    :options="options"
    label="label"
    value="value"
    placeholder="请选择"
    :disabled="false"
    :width="160"
    :height="36"
    :num="6"
    v-model="selectedValue"
    @change="onChange" />
</template>
<script>
export default {
  name: 'App',
  data () {
    return {
      options: [
        {
          label: '北京市',
          value: 1
        },
        {
          label: '上海市上海市上海市上海市',
          value: 2,
          disabled: true
        },
        {
          label: '郑州市',
          value: 3
        },
        {
          label: '纽约市纽约市纽约市纽约市',
          value: 4
        },
        {
          label: '旧金山',
          value: 5
        },
        {
          label: '悉尼市',
          value: 6
        },
        {
          label: '伦敦市',
          value: 7
        },
        {
          label: '巴黎市',
          value: 8
        }
      ],
      selectedValue: 1
    }
  },
  watch: {
    selectedValue (to) {
      console.log('selectedValue:', to)
    }
  },
  mounted () {
    setTimeout(() => { // 模拟接口调用
      this.selectedValue = 3
    }, 1000)
  },
  methods: {
    onChange (value, label, index) {
      console.log('item:', value, label, index)
    }
  }
}
</script>

如果遇到less-loader版本过高问题:

yarn add less-loader安装版本过高,报错如图
在这里插入图片描述
解决:yarn add less-loader@6.0.0

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

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

相关文章

JVM垃圾回收算法

垃圾标记阶段 对象存活判断&#xff1a;在堆里存放着几乎所有的Java对象实例&#xff0c;在GC执行垃圾回收之前&#xff0c;首先需要区分出内存中哪些是存活对象&#xff0c;哪些是已经死亡的对象。只有被标记为己经死亡的对象&#xff0c;GC才会在执行垃圾回收时&#xff0c;…

Python+人工智能基础班(通俗易懂版教学)

文章目录一、环境及工具包的介绍二、Python基本语法三、matplotlib、numpy、pandas实操四、机器学习介绍五、机器学习线性回归线性回归实战准备单因子线性回归实战多因子线性回归实战六、机器学习逻辑回归使用线性回归解决分类任务使用逻辑回归解决分类任务逻辑回归实战&#x…

在小公司工作3年,从事软件测试5年了,才发现自己还是处于“初级“水平,是不是该放弃....

毕业前三年&#xff0c;从早到晚&#xff0c;加班到深夜&#xff0c;一年又一年&#xff0c;直至刚入职场的首个黄金三年过年都去了&#xff0c;而职位却仍在原地踏步。尽管感觉自己努力过&#xff0c;但是实际上&#xff0c;自身的能力从没得到过多少提升。 所以在无数个夜晚…

生成对抗网络 | Python实现StackGAN生成对抗神经网络

生成对抗网络 | Python实现StackGAN生成对抗神经网络 目录 生成对抗网络 | Python实现StackGAN生成对抗神经网络效果一览文章概述环境准备程序设计参考资料效果一览 文章概述 生成对抗网络 | Python实现StackGAN生成对抗神经网络 环境准备 python 2.7 TensorFlow 0.12 prettyte…

Java 多线程

多线程实现方式Thread类MyThread类继承了Thread类MyThread thread new MyThread1("窗口1");thread.start();Runnable接口自定义一个MyRunnable类来实现Runnable接口&#xff0c;在MyRunnable类中重写run&#xff08;&#xff09;方法&#xff0c;创建Thread对象&…

I.MX6ULL_Linux_驱动篇(32) 设备树GPIO驱动

在前面章节中&#xff0c;我们直接在驱动文件 newchrled.c 中定义有关寄存器物理地址&#xff0c;然后使用 io_remap 函数进行内存映射&#xff0c;得到对应的虚拟地址&#xff0c;最后操作寄存 器对应的虚拟地址完成对 GPIO 的初始化。本章我们使用设备树来向 Linux 内核传递相…

劝退还是坚守?计算机视觉行业综述

劝退还是坚守&#xff1f;计算机视觉行业综述 1 从炙手可热到充满争议 计算机视觉&#xff08;Computer Vision&#xff0c;简写为CV&#xff09;是一门研究如何让计算机从图像或图像序列中获取信息并 理解其信息的学科&#xff0c;其主要目的在于从图像或图像序列中提取对世…

基于51单片机AT89C51的小型音乐喷泉控制系统设计

wx供重浩&#xff1a;创享日记 对话框发送&#xff1a;单片机小喷泉 获取完整无水印论文报告&#xff08;内含电路原理图和程序&#xff09; 根据目前音乐喷泉的发展现状&#xff0c;介绍了一个以AT89C51单片机为核心的小型音乐喷泉控制系统。给出了一个简洁的单片机控制电路&a…

Java_Spring:9. 基于 XML 的 AOP 配置

目录 1 环境搭建 1.1 第一步&#xff1a;准备必要的代码 1.2 第二步&#xff1a;拷贝必备的 jar 包到工程的 lib 目录 1.3 第三步&#xff1a;创建 spring 的配置文件并导入约束 1.4 第四步&#xff1a;配置 spring 的 ioc 1.5 第五步&#xff1a;抽取公共代码制作成通知 …

数据结构与算法笔记--数据结构与算法基本知识

目录 1--数据结构 2--算法 3--算法分析 4--实例1&#xff1a;普通算法与秦九韶算法的运算效率比较 5--实例2&#xff1a;最大子列和问题 5-1--暴力求解法 5-2--分而治之 5-3--动态规划 5-4--完整代码 1--数据结构 定义&#xff1a;所有数据元素以及数据元素之间的关系…

JS手写Promise(详细过程)

PS&#xff1a;JS手写Promise方法的整理在下一篇文章 手写Promise的API(resolve,reject,then,catch,finally,all)_Eric加油学&#xff01;的博客-CSDN博客 1、基础版Promise 首先&#xff0c;通过一个简单的Promise例子回顾其使用 const promise new Promise((resolve, rej…

为什么诚信是项目管理的关键部分?

由于有许多需要指导的活动部件和风险&#xff0c;管理一个新项目可能是一项具有挑战性的工作。在一些对质量有着严格要求的行业&#xff0c;项目结构、设定目标、跟踪状态、风险管理和资源管理等项目管理原则尤为重要&#xff0c;而领导这项工作的是诚信。那么&#xff0c;究竟…

IP 归属用 Ip2region 就够了

文章目录Ip2region 简介是什么特性支持的编程语言案例实操依赖获取IP输入流转化解析IP测试抖音、微博、小红书等各平台相继上线" 网络用户IP地址显示功能"&#xff0c; 境外显示 国家&#xff0c; 境内显示到 省市&#xff0c;且该功能无法关闭&#xff0c;IP地址为强…

【新2023Q2模拟题JAVA】华为OD机试 - 分苹果

最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为od机试,独家整理 已参加机试人员的实战技巧本篇题解:分苹果 题目 AB两个人把苹果…

第16章_变量、流程控制与游标

第16章_变量、流程控制与游标 &#x1f3e0;个人主页&#xff1a;shark-Gao &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是shark-Gao&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f389;目前状况&#xff1a;23届毕业生&#xf…

ClickHouse学习笔记(三):MergeTree 原理解析

文章目录1、简介2、MergeTree 创建方式与存储结构2.1、MergeTree 的创建方式2.2、MergeTree 的存储结构3、MergeTree 数据分区3.1、分区目录的命名规则3.2、分区目录合并过程4、一级索引4.1、索引粒度4.2、索引生成4.3、索引查询5、二级索引6、数据存储7、数据标记8、协同总结8…

BootStrap4:栅格系统

1、container容器 container&#xff1a;固定宽度的容器container-fluid&#xff1a;响应式容器 2、栅格选项 Bootstrap4 总共有五个栅格等级&#xff0c;每个响应式分界点隔出一个等级 Ps&#xff1a;.row上带有margin-left: -15px;margin-right: -15px;属性&#xff0c;你…

【22年蓝桥杯】十三届蓝桥杯真题JavaB组解析+代码(带你复习知识点)(一)

试题 A: 星期计算 【填空题】 答案&#xff1a;7 解析&#xff1a;直接对所给数进行取余&#xff0c;然后直接再加6&#xff08;注意&#xff1a;不能直接让20^226再对7进行取余操作&#xff0c;这是不对的&#xff0c;这个6可以看成已经取余过了。&#xff09; 直接取余的话可…

Linux系统安装部署及配置Grafana

TOC 用于 UI 展示 wget https://dl.grafana.com/oss/release/grafana-8.0.3-1.x86_64.rpm1 安装 grafana 1.1 下载安装 wget https://dl.grafana.com/oss/release/grafana-8.0.3-1.x86_64.rpmsudo yum install grafana-8.0.3-1.x86_64.rpm1.2 启动&状态查看 sudo syst…

PHP初级教程------------------(3)

目录 文件包含 文件包含的作用 文件包含四种形式 文件加载原理 Include和require区别 文件加载路径 文件嵌套包含 函数 函数的基本概念 函数定义语法 函数命名规范 参数详解 形参 实参 默认值 引用传递 函数体 函数返回值 ​作用域 静态变量 可变函数 匿名函数 闭包 伪类型 文件…
最新文章