javascript SmoothScroll

SmoothScroll.js
// 10/31/2017
const SmoothScroll /** @class */ = (() => {
    class SmoothScroll {
        constructor({target, scrollEase, maxOffset}) {
            const _this = this;
            this.endThreshold = 0.05;
            this.requestId = null;
            this.maxDepth = 10;
            this.viewHeight = 0;
            this.halfViewHeight = 0;
            this.maxDistance = 0;
            this.scrollHeight = 0;
            this.endScroll = 0;
            this.currentScroll = 0;
            this.resizeRequest = 1;
            this.scrollRequest = 0;
            this.scrollItems = [];
            this.lastTime = -1;
            this.maxElapsedMS = 100;
            this.targetFPMS = 0.06;
            this._onResize = event => {
                _this.resizeRequest++;
                if (!_this.requestId) {
                    _this.lastTime = performance.now();
                    _this.requestId = requestAnimationFrame(_this._update);
                }
            };
            this._onScroll = event => {
                _this.scrollRequest++;
                if (!_this.requestId) {
                    _this.lastTime = performance.now();
                    _this.requestId = requestAnimationFrame(_this._update);
                }
            };
            this._update = currentTime => {
                if (currentTime === void 0) { currentTime = performance.now(); }
                let elapsedMS = currentTime - _this.lastTime;
                if (elapsedMS > _this.maxElapsedMS) {
                    elapsedMS = _this.maxElapsedMS;
                }
                const deltaTime = elapsedMS * _this.targetFPMS;
                const dt = 1 - (1 - _this.scrollEase) ** deltaTime;
                const resized = _this.resizeRequest > 0;
                const scrollY = window.pageYOffset;
                if (resized) {
                    const height = _this.target.clientHeight;
                    document.body.style.height = `${height}px`;
                    _this.scrollHeight = height;
                    _this.viewHeight = window.innerHeight;
                    _this.halfViewHeight = _this.viewHeight / 2;
                    _this.maxDistance = _this.viewHeight * 2;
                    _this.resizeRequest = 0;
                }
                _this.endScroll = scrollY;
                // this.currentScroll += (scrollY - this.currentScroll) * this.scrollEase;
                _this.currentScroll += (scrollY - _this.currentScroll) * dt;
                if (Math.abs(scrollY - _this.currentScroll) < _this.endThreshold || resized) {
                    _this.currentScroll = scrollY;
                    _this.scrollRequest = 0;
                }
                // const scrollOrigin = scrollY + this.halfViewHeight;
                const scrollOrigin = _this.currentScroll + _this.halfViewHeight;
                _this.target.style.transform = `translate3d(0px,-${_this.currentScroll}px,0px)`;
                for (let i = 0; i < _this.scrollItems.length; i++) {
                    const item = _this.scrollItems[i];
                    const distance = scrollOrigin - item.top;
                    const offsetRatio = distance / _this.maxDistance;
                    item.endOffset = Math.round(_this.maxOffset * item.depthRatio * offsetRatio);
                    if (Math.abs(item.endOffset - item.currentOffset < _this.endThreshold)) {
                        item.currentOffset = item.endOffset;
                    }
                    else {
                        // item.currentOffset += (item.endOffset - item.currentOffset) * this.scrollEase;
                        item.currentOffset += (item.endOffset - item.currentOffset) * dt;
                    }
                    item.target.style.transform = `translate3d(0px,-${item.currentOffset}px,0px)`;
                }
                _this.lastTime = currentTime;
                _this.requestId = _this.scrollRequest > 0 ? requestAnimationFrame(_this._update) : null;
            };
            this.target = target;
            this.scrollEase = scrollEase != null ? scrollEase : 0.1;
            this.maxOffset = maxOffset != null ? maxOffset : 500;
            this.addItems();
            window.addEventListener("resize", this._onResize);
            window.addEventListener("scroll", this._onScroll);
            this._update();
        }

        addItems() {
            this.scrollItems = [];
            const elements = document.querySelectorAll("*[data-depth]");
            for (let i = 0; i < elements.length; i++) {
                const element = elements[i];
                const depth = +element.getAttribute("data-depth");
                const rect = element.getBoundingClientRect();
                const item = {
                    target: element,
                    depth,
                    top: rect.top + window.pageYOffset,
                    depthRatio: depth / this.maxDepth,
                    currentOffset: 0,
                    endOffset: 0
                };
                this.scrollItems.push(item);
            }
            return this;
        }
    }

    return SmoothScroll;
})();

javascript 自动完成组件

## Componente Autocomplete para Vuejs。 <br/> Reemplaza el Datalist HTML5 que presenta algunos problemas entre navegadores。 <br/> <br/> ### Propiedades <br/> - 输入类:clase css que se aplica al input text donde se realizalabúsqueda<br/> - 占位符:texto decampovacío(默认值:Buscar。 ..)<br/> - text:nombre de la clave del objeto quesetomarácomotext(default:text)<br/> - value:nombre de la clave del objeto quesetomarácomovalue(default:value)<br/> - 数据:array de objetos con los datos Ej。:`[{value:'...',text:'...'}]`<br/> - min-length:númeromínimodecaracteres para disparar la busqueda(默认值:3)<br/> - loading:valor booleano <br/> - loadingCaption:texto a mostrar si la propiedad loading === true(默认值:'Cargando ...')<br/> <br/> ### Eventos <br/> - 已选择:devuelve item seleccionado

AutocompleteComponent.vue
<template>
  <div>
    <div v-if="!loading">

    <input
      type="text"
      :class="inputClass"
      :placeholder="placeholder"
      v-model="terms"
      @focus="resetStatus"
      @keydown.down="onArrowDown"
      @keydown.up="onArrowUp"
      @keydown.enter="onEnter"
    />
        
    <div v-if="isVisible" class="autocomplete__results">
      <ul>
        <li
          v-for="(item, index) in results"
          :key="index"
          @click="setValue(item)"
          :class="{ 'is-active': index === arrowCounter }"
          @mouseover="arrowCounter = index"
        >{{ item[text] }}</li>
      </ul>
    </div>
    </div>
    <span v-else class="loading__caption">{{ loadingCaption }}</span>
  </div>
</template>

<script>
export default {
  props: {
    inputClass: {
      type: String
    },
    placeholder: {
      type: String
    },
    text: {
      type: String,
      default: 'text'
    },
    value: {
      type: String,
      default: 'value'
    },
    data: {
      type: Array
    },
    minLength: {
      type: Number | String,
      default: 3
    },
    loading: {
        type: Boolean,
        default: false
    },
    loadingCaption: {
        type: String,
        default: 'Cargando ...'
    }
  },
  data() {
    return {
      terms: '',
      itemSelected: false,
      arrowCounter: -1
    };
  },
  computed: {
    isVisible() {
      return this.results.length && !this.itemSelected;
    },
    results() {
      const terms = this.terms;
      if (terms.length >= this.minLength) {
        const words = terms.split(' ');
        const all = this.data.filter(item =>
          words.every(
            w => item[this.text].toLowerCase().indexOf(w.toLowerCase()) > -1
          )
        );
        return all.slice(0, 5);
      }
      return [];
    }
  },
  methods: {
    onArrowDown() {
      if (this.arrowCounter < this.results.length) {
        this.arrowCounter = this.arrowCounter + 1;
      }
    },
    onArrowUp() {
      if (this.arrowCounter > 0) {
        this.arrowCounter = this.arrowCounter - 1;
      }
    },
    onEnter() {
        const item = this.results[this.arrowCounter]
        this.setValue(item)
    },
    setValue(item) {
      this.terms = item[this.text];
      this.itemSelected = true;
      this.arrowCounter = -1
      this.$emit('selected', item);
    },
    resetStatus(e) {
      e.target.select();
      this.itemSelected = false;
    }
  }
};
</script>

<style scoped>
.autocomplete__results {
  position: absolute;
  width: 95%;
  background-color: #fff;
  z-index: 9;
  border: 1px solid #eee;
}
.autocomplete__results ul {
  margin: 0;
  list-style: none;
  padding: 0;
}

.autocomplete__results ul li {
  padding: 3px 10px;
  cursor: pointer;
  font-size: 12px;
}

.autocomplete__results ul li.is-active {
  background-color: #4aaeb9;
  color: white;
}

.loading__caption {
    font-size: 12px;
}
</style>

javascript ESLint + Prettier + TypeScript

.eslintrc.js
module.exports = {
  env: {
    browser: true,
    es6: true
  },
  parser: "@typescript-eslint/parser",
  extends: [
    "airbnb",
    "plugin:react/recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:prettier/recommended",
    "prettier/react",
    "prettier/@typescript-eslint"
  ],
  plugins: ["@typescript-eslint", "prettier", "react", "only-warn"],
  parserOptions: {
    ecmaVersion: 2018,
    sourceType: "module",
    ecmaFeatures: {
      jsx: true
    }
  },
  rules: {
    "max-lines": 1, // default 300 lines
    "react/jsx-filename-extension": [1, { "extensions": [".tsx"] }],
    "prettier/prettier": [1, { singleQuote: true }]
  },
  settings: {
    react: {
      version: "detect"
    },
    "import/resolver": {
      node: {
        extensions: [".ts", ".tsx"]
      }
    }
  }
};

javascript cms directus

cms.js
{url del servidor}/{nombre del proyecto}/items/{nombre del componente que queremos consultar}
+ pedir campos específicos:
  - ?fields={campo de primer nivel}.{campo del segundo nivel}
    - puedo expandir todo un nivel: ?fields?{campo de primer nivel}.* -> objectos (relaciones) y listas, hay que expandirlos
+ filtrar por campos
  - ?filter=[{nombre del campo}]={valor}
https://qadirectus.tous.private/_/items/page_category?fields=basic_slider.slides.c_basic_slider_slide_id.*.*.*&filterexternal_id=2899
+ &single=true
se utiliza para que lo que te devuelve te convierta de un array a un objeto

- QA
URL del servidor: https://qadirectus.tous.private
Nombre del proyecto: _

https://qadirectus.tous.private/_/items/page_category?fields=basic_slider.id

- Petición
https://qadirectus.tous.private/_/items/page_category?filter[external_id]=2899&single=true&fields=basic_slider.slides.c_basic_slider_slide_id.*.*.*

javascript Firebase获取数据

fetch.js
    constructor(props) {
        super(props);

        this.state = ({
            busList: '',
            busLists: []
        })
    }

    componentDidMount() {
        firebase.database().ref().child('busList/').once('value', snapshot => {
            const data = snapshot.val()
            if(snapshot.val()) {
                const initMessages = [];
                Object.keys(data).forEach(busList => initMessages.push(data[busList]));
                this.setState({
                    busLists: initMessages
                })
            }
        })

        firebase.database().ref().child('busList/').on("child_added", snapshot =>{
            const data = snapshot.val();
            if(data) {
                this.setState(prevState => ({
                    busLists: [data, ...prevState.busLists]
                }))
            }
        }) 
    }
App.js
  render() {
    return (
      <View >
        <View >
          <FlatList
            data = {this.state.busLists}
            renderItem = {({item}) => (
                <View>
                    <Text>{item}</Text>
                </View>   
            )}
          />
        </View>
      </View>
    );
  }
}

javascript 多个对象合成一个新的对象

mix
function mix(...mixins) {
  class Mix {
    constructor() {
      for (let mixin of mixins) {
        copyProperties(this, new mixin()); // 拷贝实例属性
      }
    }
  }

  for (let mixin of mixins) {
    copyProperties(Mix, mixin); // 拷贝静态属性
    copyProperties(Mix.prototype, mixin.prototype); // 拷贝原型属性
  }

  return Mix;
}

function copyProperties(target, source) {
  for (let key of Reflect.ownKeys(source)) {
    if ( key !== 'constructor'
      && key !== 'prototype'
      && key !== 'name'
    ) {
      let desc = Object.getOwnPropertyDescriptor(source, key);
      Object.defineProperty(target, key, desc);
    }
  }
}

javascript AMD / CJS /其他

base.js
(function(global, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD に対応した部分
    define(['myModule', 'myOtherModule'], factory);
  }
  else if (typeof exports === 'object') {
    // CommonJS に対応した部分
    module.exports = factory(require('myModule'), require('myOtherModule'));
  }
  else {
    // それ以外のブラウザでの利用に対応した部分 (引数 global に window を指定することで対応する)
    global.returnExports = factory(global.myModule, root.myOtherModule);
  }
}(this, function(myModule, myOtherModule) {
  // Methods
  function notHelloOrGoodbye() {}; // A private method
  function hello() {}; // A public method because it's returned (see below)
  function goodbye() {}; // A public method because it's returned (see below)
  
  // Exposed public methods
  return {
    hello: hello,
    goodbye: goodbye
  };
}));

javascript 用htmlspecialchars

htmlspecialchars
function escapeHtml(str) {
    const map = {
        '&': '&amp;',
        '<': '&lt;',
        '>': '&gt;',
        '"': '&quot;',
        "'": '&#039;'
    };
    return str.replace(/[&<>"']/g, function(m) {
        return map[m];
    });
}

function decodeHtml(str) {
    const map = {
        '&amp;': '&',
        '&lt;': '<',
        '&gt;': '>',
        '&quot;': '"',
        '&#039;': "'"
    };
    return str.replace(/&amp;|&lt;|&gt;|&quot;|&#039;/g, function(m) {
        return map[m];
    });
}

javascript axios api电话

使用axios的通用api调用,然后可以将其放置在一个反应​​useEffect()挂钩中,该挂钩具有您要设置的状态切片

Foobar.js
import axios from 'axios';

export function Foobar(setter) {
  axios
    .get(/** api call inset here **/)
    .then(res => setter(res.data))
    .catch(err => console.log(err));
}

/**
 * can then import
 * and call with name in another file
 * for eaxmple
 * import Foobar from './Foobar';
 * // then use in useEffect()
 * Foobar(setVariableNameForData);
 * then you could reuse this elsewhere.
 */

javascript 反应路由器挂钩

useRoutes.js
import { useContext, useEffect } from 'react';
import { __RouterContext } from 'react-router';
import useForceUpdate from 'use-force-update';

const useRouter = () => {
	// Re Rendering
	const forceUpdate = useForceUpdate();
	// Getting Router Context
	const routerContext = useContext(__RouterContext);

	useEffect(() => routerContext.history.listen(forceUpdate), [routerContext]);

	return routerContext;
};

export default useRouter;