zoukankan      html  css  js  c++  java
  • element color-picker源码

    src/main.vue

    <template>
      <div
        :class="[
          'el-color-picker',
          colorDisabled ? 'is-disabled' : '',
          colorSize ? `el-color-picker--${ colorSize }` : ''
        ]"
        v-clickoutside="hide">
        <div class="el-color-picker__mask" v-if="colorDisabled"></div>
        <div class="el-color-picker__trigger" @click="handleTrigger">
          <span class="el-color-picker__color" :class="{ 'is-alpha': showAlpha }">
            <span class="el-color-picker__color-inner"
              :style="{
                backgroundColor: displayedColor
              }"></span>
            <span class="el-color-picker__empty el-icon-close" v-if="!value && !showPanelColor"></span>
          </span>
          <span class="el-color-picker__icon el-icon-arrow-down" v-show="value || showPanelColor"></span>
        </div>
        <picker-dropdown
           ref="dropdown"
           :class="['el-color-picker__panel', popperClass || '']"
           v-model="showPicker"
           @pick="confirmValue"
           @clear="clearValue"
           :color="color"
           :show-alpha="showAlpha"
           :predefine="predefine">
        </picker-dropdown>
      </div>
    </template>
    
    <script>
      import Color from './color';
      import PickerDropdown from './components/picker-dropdown.vue';
      import Clickoutside from 'element-ui/src/utils/clickoutside';
      import Emitter from 'element-ui/src/mixins/emitter';
    
      export default {
        name: 'ElColorPicker',
    
        mixins: [Emitter],
    
        props: {
          // value / v-model    绑定值  string
          value: String,
          // 是否支持透明度选择
          showAlpha: Boolean,
          // 写入 v-model 的颜色的格式    string    hsl / hsv / hex / rgb    hex(show-alpha 为 false)/ rgb(show-alpha 为 true)
          colorFormat: String,
          // 是否禁用
          disabled: Boolean,
          // 尺寸
          size: String,
          // ColorPicker 下拉框的类名
          popperClass: String,
          // 预定义颜色
          predefine: Array
        },
    
        inject: {
          elForm: {
            default: ''
          },
          elFormItem: {
            default: ''
          }
        },
        // 自定义指令,点击元素外面事件
        directives: { Clickoutside },
    
        computed: {
          // 背景色调用了 displayedColor 这个 computed 属性:
          displayedColor() {
            if (!this.value && !this.showPanelColor) {
              return 'transparent';
            }
    
            return this.displayedRgb(this.color, this.showAlpha);
          },
    
          _elFormItemSize() {
            return (this.elFormItem || {}).elFormItemSize;
          },
    
          colorSize() {
            return this.size || this._elFormItemSize || (this.$ELEMENT || {}).size;
          },
    
          colorDisabled() {
            return this.disabled || (this.elForm || {}).disabled;
          }
        },
    
        watch: {
          value(val) {
            if (!val) {
              this.showPanelColor = false;
            } else if (val && val !== this.color.value) {
              this.color.fromString(val);
            }
          },
          color: {
            // 深度监视
            deep: true,
            // 自定义监听事件
            handler() {
              this.showPanelColor = true;
            }
          },
          // 监听背景色改变,转换成rgb颜色往上传递,
          displayedColor(val) {
            if (!this.showPicker) return;
            // 新建一个color类
            const currentValueColor = new Color({
              enableAlpha: this.showAlpha, // props接收的是否支持透明度选择
              format: this.colorFormat, // props接收的写入v-model颜色格式
            });
            currentValueColor.fromString(this.value);
            // 转换成rgb格式
            const currentValueColorRgb = this.displayedRgb(currentValueColor, this.showAlpha);
            if (val !== currentValueColorRgb) {
              // 面板中当前显示的颜色发生改变时触发
              this.$emit('active-change', val);
            }
          }
        },
    
        methods: {
          // 展开/关闭下拉面板
          handleTrigger() {
            if (this.colorDisabled) return;
            this.showPicker = !this.showPicker;
          },
          // 点击面板确定按钮
          confirmValue() {
            const value = this.color.value;
            // 当绑定值变化时触发
            this.$emit('input', value);
            this.$emit('change', value);
            // 往上通知el-form
            this.dispatch('ElFormItem', 'el.form.change', value);
            this.showPicker = false;
          },
          // 点击面板清空按钮
          clearValue() {
            this.$emit('input', null);
            this.$emit('change', null);
            if (this.value !== null) {
              this.dispatch('ElFormItem', 'el.form.change', null);
            }
            this.showPanelColor = false;
            this.showPicker = false;
            this.resetColor();
          },
          // 点击元素外自定义指令
          hide() {
            this.showPicker = false;
            this.resetColor();
          },
          // 重置颜色值
          resetColor() {
            this.$nextTick(_ => {
              if (this.value) {
                this.color.fromString(this.value);
              } else {
                this.showPanelColor = false;
              }
            });
          },
          // 将color转变为rgb(a)模式
          displayedRgb(color, showAlpha) {
            if (!(color instanceof Color)) {
              throw Error('color should be instance of Color Class');
            }
    
            const { r, g, b } = color.toRgb();
            return showAlpha
              ? `rgba(${ r }, ${ g }, ${ b }, ${ color.get('alpha') / 100 })`
              : `rgb(${ r }, ${ g }, ${ b })`;
          }
        },
    
        mounted() {
          const value = this.value;
          if (value) {
            this.color.fromString(value);
          }
          this.popperElm = this.$refs.dropdown.$el;
        },
    
        data() {
          // 新建color类,并赋值
          const color = new Color({
            enableAlpha: this.showAlpha,
            format: this.colorFormat
          });
    
          return {
            color,
            showPicker: false,
            showPanelColor: false
          };
        },
    
        components: {
          PickerDropdown
        }
      };
    </script>

    src/components/picker-dropdown.vue

    <template>
      <transition name="el-zoom-in-top" @after-leave="doDestroy">
        <div
          class="el-color-dropdown"
          v-show="showPopper">
          <div class="el-color-dropdown__main-wrapper">
            <!-- 接收父组件传递的color对象,传递给子组件 -->
            <hue-slider ref="hue" :color="color" vertical style="float: right;"></hue-slider>
            <sv-panel ref="sl" :color="color"></sv-panel>
          </div>
          <alpha-slider v-if="showAlpha" ref="alpha" :color="color"></alpha-slider>
          <!-- predefine, 父组件props接收额预定义颜色 -->
          <predefine v-if="predefine" :color="color" :colors="predefine"></predefine>
          <div class="el-color-dropdown__btns">
            <span class="el-color-dropdown__value">
              <el-input
                v-model="customInput"
                @keyup.native.enter="handleConfirm"
                @blur="handleConfirm"
                :validate-event="false"
                size="mini">
              </el-input>
            </span>
            <el-button
              size="mini"
              type="text"
              class="el-color-dropdown__link-btn"
              @click="$emit('clear')">
              {{ t('el.colorpicker.clear') }}
            </el-button>
            <el-button
              plain
              size="mini"
              class="el-color-dropdown__btn"
              @click="confirmValue">
              {{ t('el.colorpicker.confirm') }}
            </el-button>
          </div>
        </div>
      </transition>
    </template>
    
    <script>
      import SvPanel from './sv-panel';
      import HueSlider from './hue-slider';
      import AlphaSlider from './alpha-slider';
      import Predefine from './predefine';
      import Popper from 'element-ui/src/utils/vue-popper';
      import Locale from 'element-ui/src/mixins/locale';
      import ElInput from 'element-ui/packages/input';
      import ElButton from 'element-ui/packages/button';
    
      export default {
        name: 'el-color-picker-dropdown',
    
        mixins: [Popper, Locale],
    
        components: {
          SvPanel,
          HueSlider,
          AlphaSlider,
          ElInput,
          ElButton,
          Predefine
        },
    
        props: {
          color: {
            required: true
          },
          showAlpha: Boolean,
          predefine: Array
        },
    
        data() {
          return {
            customInput: ''
          };
        },
    
        computed: {
          // 中间传递作用,接收父组件value值传
          currentColor() {
            const parent = this.$parent;
            return !parent.value && !parent.showPanelColor ? '' : parent.color.value;
          }
        },
    
        methods: {
          // 点击确认按钮
          confirmValue() {
            this.$emit('pick');
          },
          // 按Enter键或失焦的时候
          handleConfirm() {
            //  转换input框中的值
            this.color.fromString(this.customInput);
          }
        },
    
        mounted() {
          this.$parent.popperElm = this.popperElm = this.$el;
          this.referenceElm = this.$parent.$el;
        },
    
        watch: {
          showPopper(val) {
            if (val === true) {
              this.$nextTick(() => {
                const { sl, hue, alpha } = this.$refs;
                sl && sl.update();
                hue && hue.update();
                alpha && alpha.update();
              });
            }
          },
          // 子组件监听此变量改变事件
          currentColor: {
            immediate: true,
            handler(val) {
              this.customInput = val;
            }
          }
        }
      };
    </script>

    src/color.js

    /*
      其实 color.js 主要是定义了一个 Color 类,简单说下其中一些方法的作用:
      set 用于设置 Color 中的变量。
      get 用于获取 _hue _saturation _value _alpha 这四个值。
      toRgb 方法将当前颜色的值(除了透明度)以 RGB 的形式返回。
      fromString 方法将传入的颜色值解析成 HSV 格式,并赋值给 _hue _saturation _value 和 _alpha。
      doOnChange 方法将会计算颜色值组成字符串传给 value。
    */
    
    // hsv 转 hsl
    const hsv2hsl = function (hue, sat, val) {
      return [
        hue,
        (sat * val / ((hue = (2 - sat) * val) < 1 ? hue : 2 - hue)) || 0,
        hue / 2
      ];
    };
    
    // Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1
    // <http://stackoverflow.com/questions/7422072/javascript-how-to-detect-number-as-a-decimal-including-1-0>
    // 是否为 1.0
    const isOnePointZero = function (n) {
      return typeof n === 'string' && n.indexOf('.') !== -1 && parseFloat(n) === 1;
    };
    // 是否为百分比
    const isPercentage = function (n) {
      return typeof n === 'string' && n.indexOf('%') !== -1;
    };
    
    // Take input from [0, n] and return it as [0, 1]
    const bound01 = function (value, max) {
      if (isOnePointZero(value)) value = '100%';
    
      const processPercent = isPercentage(value);
      value = Math.min(max, Math.max(0, parseFloat(value)));
    
      // Automatically convert percentage into number
      if (processPercent) {
        value = parseInt(value * max, 10) / 100;
      }
    
      // Handle floating point rounding errors
      if ((Math.abs(value - max) < 0.000001)) {
        return 1;
      }
    
      // Convert into [0, 1] range if it isn't already
      return (value % max) / parseFloat(max);
    };
    // 十进制转十六进制
    const INT_HEX_MAP = { 10: 'A', 11: 'B', 12: 'C', 13: 'D', 14: 'E', 15: 'F' };
    // 转为十六进制颜色值
    const toHex = function ({ r, g, b }) {
      const hexOne = function (value) {
        value = Math.min(Math.round(value), 255);
        const high = Math.floor(value / 16);
        const low = value % 16;
        return '' + (INT_HEX_MAP[high] || high) + (INT_HEX_MAP[low] || low);
      };
    
      if (isNaN(r) || isNaN(g) || isNaN(b)) return '';
    
      return '#' + hexOne(r) + hexOne(g) + hexOne(b);
    };
    // 十六进制转十进制
    const HEX_INT_MAP = { A: 10, B: 11, C: 12, D: 13, E: 14, F: 15 };
    // 解析十六进制
    const parseHexChannel = function (hex) {
      if (hex.length === 2) {
        return (HEX_INT_MAP[hex[0].toUpperCase()] || +hex[0]) * 16 + (HEX_INT_MAP[hex[1].toUpperCase()] || +hex[1]);
      }
    
      return HEX_INT_MAP[hex[1].toUpperCase()] || +hex[1];
    };
    // hsl 转 hsv
    const hsl2hsv = function (hue, sat, light) {
      sat = sat / 100;
      light = light / 100;
      let smin = sat;
      const lmin = Math.max(light, 0.01);
      let sv;
      let v;
    
      light *= 2;
      sat *= (light <= 1) ? light : 2 - light;
      smin *= lmin <= 1 ? lmin : 2 - lmin;
      v = (light + sat) / 2;
      sv = light === 0 ? (2 * smin) / (lmin + smin) : (2 * sat) / (light + sat);
    
      return {
        h: hue,
        s: sv * 100,
        v: v * 100
      };
    };
    
    // `rgbToHsv`
    // Converts an RGB color value to HSV
    // *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1]
    // *Returns:* { h, s, v } in [0,1]
    // rgb 转 hsv
    const rgb2hsv = function (r, g, b) {
      r = bound01(r, 255);
      g = bound01(g, 255);
      b = bound01(b, 255);
    
      const max = Math.max(r, g, b);
      const min = Math.min(r, g, b);
      let h, s;
      let v = max;
    
      const d = max - min;
      s = max === 0 ? 0 : d / max;
    
      if (max === min) {
        h = 0; // achromatic
      } else {
        switch (max) {
          case r:
            h = (g - b) / d + (g < b ? 6 : 0);
            break;
          case g:
            h = (b - r) / d + 2;
            break;
          case b:
            h = (r - g) / d + 4;
            break;
        }
        h /= 6;
      }
    
      return { h: h * 360, s: s * 100, v: v * 100 };
    };
    
    // `hsvToRgb`
    // Converts an HSV color value to RGB.
    // *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100]
    // *Returns:* { r, g, b } in the set [0, 255]
    // hsv 转 rgb
    const hsv2rgb = function (h, s, v) {
      h = bound01(h, 360) * 6;
      s = bound01(s, 100);
      v = bound01(v, 100);
    
      const i = Math.floor(h);
      const f = h - i;
      const p = v * (1 - s);
      const q = v * (1 - f * s);
      const t = v * (1 - (1 - f) * s);
      const mod = i % 6;
      const r = [v, q, p, p, t, v][mod];
      const g = [t, v, v, q, p, p][mod];
      const b = [p, p, t, v, v, q][mod];
    
      return {
        r: Math.round(r * 255),
        g: Math.round(g * 255),
        b: Math.round(b * 255)
      };
    };
    
    export default class Color {
      constructor(options) {
        this._hue = 0;
        this._saturation = 100;
        this._value = 100;
        this._alpha = 100;
    
        this.enableAlpha = false;
        this.format = 'hex';
        this.value = '';
    
        options = options || {};
    
        for (let option in options) {
          if (options.hasOwnProperty(option)) {
            this[option] = options[option];
          }
        }
    
        this.doOnChange();
      }
    
      set (prop, value) {
        if (arguments.length === 1 && typeof prop === 'object') {
          for (let p in prop) {
            if (prop.hasOwnProperty(p)) {
              this.set(p, prop[p]);
            }
          }
    
          return;
        }
    
        this['_' + prop] = value;
        this.doOnChange();
      }
      // 获取属性值 _hue
      get (prop) {
        return this['_' + prop];
      }
      // 颜色值转为 rgb 返回
      toRgb () {
        return hsv2rgb(this._hue, this._saturation, this._value);
      }
      // 格式化传入的值
      fromString (value) {
        if (!value) {
          this._hue = 0;
          this._saturation = 100;
          this._value = 100;
    
          this.doOnChange();
          return;
        }
        // 定义计算出结果后:赋值、改变。
        const fromHSV = (h, s, v) => {
          this._hue = Math.max(0, Math.min(360, h));
          this._saturation = Math.max(0, Math.min(100, s));
          this._value = Math.max(0, Math.min(100, v));
    
          this.doOnChange();
        };
    
        if (value.indexOf('hsl') !== -1) {
          const parts = value.replace(/hsla|hsl|(|)/gm, '')
            .split(/s|,/g).filter((val) => val !== '').map((val, index) => index > 2 ? parseFloat(val) : parseInt(val, 10));
    
          if (parts.length === 4) {
            this._alpha = Math.floor(parseFloat(parts[3]) * 100);
          } else if (parts.length === 3) {
            this._alpha = 100;
          }
          if (parts.length >= 3) {
            const { h, s, v } = hsl2hsv(parts[0], parts[1], parts[2]);
            fromHSV(h, s, v);
          }
        } else if (value.indexOf('hsv') !== -1) {
          const parts = value.replace(/hsva|hsv|(|)/gm, '')
            .split(/s|,/g).filter((val) => val !== '').map((val, index) => index > 2 ? parseFloat(val) : parseInt(val, 10));
    
          if (parts.length === 4) {
            this._alpha = Math.floor(parseFloat(parts[3]) * 100);
          } else if (parts.length === 3) {
            this._alpha = 100;
          }
          if (parts.length >= 3) {
            fromHSV(parts[0], parts[1], parts[2]);
          }
        } else if (value.indexOf('rgb') !== -1) {
          const parts = value.replace(/rgba|rgb|(|)/gm, '')
            .split(/s|,/g).filter((val) => val !== '').map((val, index) => index > 2 ? parseFloat(val) : parseInt(val, 10));
    
          if (parts.length === 4) {
            this._alpha = Math.floor(parseFloat(parts[3]) * 100);
          } else if (parts.length === 3) {
            this._alpha = 100;
          }
          if (parts.length >= 3) {
            const { h, s, v } = rgb2hsv(parts[0], parts[1], parts[2]);
            fromHSV(h, s, v);
          }
        } else if (value.indexOf('#') !== -1) {
          const hex = value.replace('#', '').trim();
          if (!/^(?:[0-9a-fA-F]{3}){1,2}$/.test(hex)) return;
          let r, g, b;
    
          if (hex.length === 3) {
            r = parseHexChannel(hex[0] + hex[0]);
            g = parseHexChannel(hex[1] + hex[1]);
            b = parseHexChannel(hex[2] + hex[2]);
          } else if (hex.length === 6 || hex.length === 8) {
            r = parseHexChannel(hex.substring(0, 2));
            g = parseHexChannel(hex.substring(2, 4));
            b = parseHexChannel(hex.substring(4, 6));
          }
    
          if (hex.length === 8) {
            this._alpha = Math.floor(parseHexChannel(hex.substring(6)) / 255 * 100);
          } else if (hex.length === 3 || hex.length === 6) {
            this._alpha = 100;
          }
    
          const { h, s, v } = rgb2hsv(r, g, b);
          fromHSV(h, s, v);
        }
      }
    
      compare (color) {
        return Math.abs(color._hue - this._hue) < 2 &&
          Math.abs(color._saturation - this._saturation) < 1 &&
          Math.abs(color._value - this._value) < 1 &&
          Math.abs(color._alpha - this._alpha) < 1;
      }
      // 更具计算结果定义当前颜色值 value
      doOnChange () {
        const { _hue, _saturation, _value, _alpha, format } = this;
    
        if (this.enableAlpha) {
          switch (format) {
            case 'hsl':
              const hsl = hsv2hsl(_hue, _saturation / 100, _value / 100);
              this.value = `hsla(${_hue}, ${Math.round(hsl[1] * 100)}%, ${Math.round(hsl[2] * 100)}%, ${_alpha / 100})`;
              break;
            case 'hsv':
              this.value = `hsva(${_hue}, ${Math.round(_saturation)}%, ${Math.round(_value)}%, ${_alpha / 100})`;
              break;
            default:
              const { r, g, b } = hsv2rgb(_hue, _saturation, _value);
              this.value = `rgba(${r}, ${g}, ${b}, ${_alpha / 100})`;
          }
        } else {
          switch (format) {
            case 'hsl':
              const hsl = hsv2hsl(_hue, _saturation / 100, _value / 100);
              this.value = `hsl(${_hue}, ${Math.round(hsl[1] * 100)}%, ${Math.round(hsl[2] * 100)}%)`;
              break;
            case 'hsv':
              this.value = `hsv(${_hue}, ${Math.round(_saturation)}%, ${Math.round(_value)}%)`;
              break;
            case 'rgb':
              const { r, g, b } = hsv2rgb(_hue, _saturation, _value);
              this.value = `rgb(${r}, ${g}, ${b})`;
              break;
            default:
              this.value = toHex(hsv2rgb(_hue, _saturation, _value));
          }
        }
      }
    };

    src/draggable.js

    // 选择器拖动效果逻辑
    import Vue from 'vue';
    let isDragging = false;
    
    export default function (element, options) {
      if (Vue.prototype.$isServer) return;
      // 移动函数
      const moveFn = function (event) {
        if (options.drag) {
          options.drag(event);
        }
      };
      // 抬起函数
      const upFn = function (event) {
        // 移除鼠标移动监听
        document.removeEventListener('mousemove', moveFn);
        // 移除鼠标抬起监听
        document.removeEventListener('mouseup', upFn);
        document.onselectstart = null;
        document.ondragstart = null;
    
        isDragging = false;
        // 结束
        if (options.end) {
          options.end(event);
        }
      };
      // 给元素添加鼠标按下事件监听
      element.addEventListener('mousedown', function (event) {
        if (isDragging) return;
        // 禁止选择,禁止复制
        document.onselectstart = function () { return false; };
        //禁止鼠标拖动,如拖动图片、连接等
        document.ondragstart = function () { return false; };
        // 给元素添加鼠标移动和鼠标抬起事件监听
        document.addEventListener('mousemove', moveFn);
        document.addEventListener('mouseup', upFn);
        isDragging = true;
        // 开始
        if (options.start) {
          options.start(event);
        }
      });
    }

    src/components/alpha-slider.vue     src/components/hue-slider.vue   src/components/sv-panel.vue三个文件差不多不重复了  

    <template>
    <!-- 透明度选择器 -->
      <div class="el-color-alpha-slider" :class="{ 'is-vertical': vertical }">
        <div class="el-color-alpha-slider__bar"
             @click="handleClick"
             ref="bar"
             :style="{
               background: background
             }">
        </div>
        <div class="el-color-alpha-slider__thumb"
             ref="thumb"
             :style="{
               left: thumbLeft + 'px',
               top: thumbTop + 'px'
             }">
        </div>
      </div>
    </template>
    
    <script>
      import draggable from '../draggable';
    
      export default {
        name: 'el-color-alpha-slider',
    
        props: {
          color: {
            required: true
          },
          vertical: Boolean
        },
    
        watch: {
          'color._alpha'() {
            this.update();
          },
    
          'color.value'() {
            this.update();
          }
        },
    
        methods: {
          handleClick(event) {
            const thumb = this.$refs.thumb;
            const target = event.target;
    
            if (target !== thumb) {
              this.handleDrag(event);
            }
          },
    
          handleDrag(event) {
            const rect = this.$el.getBoundingClientRect();
            const { thumb } = this.$refs;
    
            if (!this.vertical) {
              let left = event.clientX - rect.left;
              left = Math.max(thumb.offsetWidth / 2, left);
              left = Math.min(left, rect.width - thumb.offsetWidth / 2);
    
              this.color.set('alpha', Math.round((left - thumb.offsetWidth / 2) / (rect.width - thumb.offsetWidth) * 100));
            } else {
              let top = event.clientY - rect.top;
              top = Math.max(thumb.offsetHeight / 2, top);
              top = Math.min(top, rect.height - thumb.offsetHeight / 2);
    
              this.color.set('alpha', Math.round((top - thumb.offsetHeight / 2) / (rect.height - thumb.offsetHeight) * 100));
            }
          },
    
          getThumbLeft() {
            if (this.vertical) return 0;
            const el = this.$el;
            const alpha = this.color._alpha;
    
            if (!el) return 0;
            const thumb = this.$refs.thumb;
            return Math.round(alpha * (el.offsetWidth - thumb.offsetWidth / 2) / 100);
          },
    
          getThumbTop() {
            if (!this.vertical) return 0;
            const el = this.$el;
            const alpha = this.color._alpha;
    
            if (!el) return 0;
            const thumb = this.$refs.thumb;
            return Math.round(alpha * (el.offsetHeight - thumb.offsetHeight / 2) / 100);
          },
    
          getBackground() {
            if (this.color && this.color.value) {
              const { r, g, b } = this.color.toRgb();
              return `linear-gradient(to right, rgba(${r}, ${g}, ${b}, 0) 0%, rgba(${r}, ${g}, ${b}, 1) 100%)`;
            }
            return null;
          },
    
          update() {
            this.thumbLeft = this.getThumbLeft();
            this.thumbTop = this.getThumbTop();
            this.background = this.getBackground();
          }
        },
    
        data() {
          return {
            thumbLeft: 0,
            thumbTop: 0,
            background: null
          };
        },
    
        mounted() {
          const { bar, thumb } = this.$refs;
    
          const dragConfig = {
            drag: (event) => {
              this.handleDrag(event);
            },
            end: (event) => {
              this.handleDrag(event);
            }
          };
    
          draggable(bar, dragConfig);
          draggable(thumb, dragConfig);
          this.update();
        }
      };
    </script>
  • 相关阅读:
    day12_函数
    day12_游标
    day12_序列——重置序列
    day12_序列——oracle主键自动增加
    day12_B2B用户禁止PLSQL登录
    七月未央,安之若素
    php----显示中文乱码的问题
    C#--中实现邮件发送
    C#--使用存储过程
    C#--之文件操作
  • 原文地址:https://www.cnblogs.com/wsk1576025821/p/10943656.html
Copyright © 2011-2022 走看看