Skip to main content

· 4 min read
本地多个包相互依赖,如何去本地npm安装并测试呢?

项目结构

npmTest
├─ .DS_Store
├─ a
│ ├─ .DS_Store
│ ├─ index.mjs
│ ├─ package-lock.json
│ └─ package.json
├─ b
│ ├─ .DS_Store
│ ├─ index.mjs
│ └─ package.json
└─ c
├─ index.mjs
└─ package.json

假设有三个package

a项目依赖b项目,b项目依赖c项目 安装的时候只在a项目下安装依赖,即npm install --save ./b

a -> package.json 如下:

  {
"name": "b",
"version": "2.0.0",
"description": "",
"main": "index.mjs",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"c": "file:../c"
}
}

a -> index.mjs 如下:

  import c from 'c';

export default c;

a -> node_modules 目录结构 如下:

node_modules
├─ b
│ ├─ node_modules
│ ├─ c
| ├─ index.mjs
| ├─ package.json

a项目node_modules里面b依赖包会与 ./b 建立软连接,方便开发在本地调试。

查看npm解析安装依赖包详细情况

npm install --verbose (打印详细信息) npm install --loglevel silly (答应更加具体的解析安装详情) npm install --loglevel silly 2>&1 | tee log.txt (输出安装依赖信息到log.txt文件中 2>&1 输出成单个流; tee 读取标准输入到数据,并将内容输出成文件)

npm info it worked if it ends with ok
npm verb cli [
npm verb cli '/usr/local/bin/node',
npm verb cli '/usr/local/bin/npm',
npm verb cli 'install',
npm verb cli '--loglevel',
npm verb cli 'silly'
npm verb cli ]
npm info using npm@6.14.15
npm info using node@v14.16.0
npm verb npm-session 85e124dc20badd09
npm sill install runPreinstallTopLevelLifecycles
npm sill preinstall a@1.0.0
npm info lifecycle a@1.0.0~preinstall: a@1.0.0
npm sill install loadCurrentTree
npm sill install readLocalPackageData
npm timing stage:loadCurrentTree Completed in 9ms
npm sill install loadIdealTree
npm sill install cloneCurrentTreeToIdealTree
npm timing stage:loadIdealTree:cloneCurrentTree Completed in 1ms
npm sill install loadShrinkwrap
npm timing stage:loadIdealTree:loadShrinkwrap Completed in 6ms
npm sill install loadAllDepsIntoIdealTree
npm timing stage:loadIdealTree:loadAllDepsIntoIdealTree Completed in 3ms
npm timing stage:loadIdealTree Completed in 11ms
npm sill currentTree a@1.0.0
npm sill currentTree └─┬ b@2.0.0
npm sill currentTree └── c@1.0.0
npm sill idealTree a@1.0.0
npm sill idealTree └─┬ b@2.0.0
npm sill idealTree └── c@1.0.0
npm sill install generateActionsToTake
npm timing stage:generateActionsToTake Completed in 2ms
npm sill diffTrees action count 0
npm sill decomposeActions action count 0
npm sill install executeActions
npm sill doSerial global-install 0
npm verb correctMkdir /Users/xf/.npm/_locks correctMkdir not in flight; initializing
npm verb lock using /Users/xf/.npm/_locks/staging-cc44cd3a0fd01acc.lock for /Users/xf/Documents/Test/test/js/npmTest/a/node_modules/.staging
npm sill doParallel extract 0
npm sill doReverseSerial unbuild 0
npm sill doSerial remove 0
npm sill doSerial move 0
npm sill doSerial finalize 0
npm sill doParallel refresh-package-json 0
npm sill doParallel preinstall 0
npm sill doSerial build 0
npm sill doSerial global-link 0
npm sill doParallel update-linked 0
npm sill doSerial install 0
npm sill doSerial postinstall 0
npm verb unlock done using /Users/xf/.npm/_locks/staging-cc44cd3a0fd01acc.lock for /Users/xf/Documents/Test/test/js/npmTest/a/node_modules/.staging
npm timing stage:executeActions Completed in 29ms
npm timing stage:rollbackFailedOptional Completed in 0ms
npm sill install runPostinstallTopLevelLifecycles
npm sill build a@1.0.0
npm info linkStuff a@1.0.0
npm sill linkStuff a@1.0.0 has /Users/xf/Documents/Test/test/js/npmTest as its parent node_modules
npm sill install a@1.0.0
npm info lifecycle a@1.0.0~install: a@1.0.0
npm sill postinstall a@1.0.0
npm info lifecycle a@1.0.0~postinstall: a@1.0.0
npm sill prepublish a@1.0.0
npm info lifecycle a@1.0.0~prepublish: a@1.0.0
npm info lifecycle a@1.0.0~prepare: a@1.0.0
npm timing stage:runTopLevelLifecycles Completed in 81ms
npm sill saveTree a@1.0.0 // 依赖的结构
npm sill saveTree └─┬ b@2.0.0
npm sill saveTree └── c@1.0.0
npm sill install saveToDependencies
npm verb saving []
npm verb shrinkwrap skipping write for package.json because there were no changes.
npm info lifecycle undefined~preshrinkwrap: undefined
npm info lifecycle a@1.0.0~shrinkwrap: a@1.0.0
npm verb shrinkwrap skipping write for package-lock.json because there were no changes.
npm info lifecycle a@1.0.0~postshrinkwrap: a@1.0.0
npm WARN a@1.0.0 No description
npm WARN a@1.0.0 No repository field.

npm sill install printInstalled
npm timing audit submit Completed in 511ms
npm http fetch POST 200 https://registry.yarnpkg.com/-/npm/v1/security/audits/quick 512ms
npm timing audit body Completed in 2ms
audited 2 packages in 0.565s
found 0 vulnerabilities

npm verb exit [ 0, true ]
npm timing npm Completed in 906ms
npm info ok

· 3 min read

是一种混合稳定的排序算法,源自合并排序和插入排序,旨在较好地处理真实世界中各种各样的数据。

实现

// C++ program to perform TimSort.
#include<bits/stdc++.h>
using namespace std;
const int RUN = 32;

// This function sorts array from left index to
// to right index which is of size atmost RUN
void insertionSort(int arr[], int left, int right)
{
for (int i = left + 1; i <= right; i++)
{
int temp = arr[i];
int j = i - 1;
while (j >= left && arr[j] > temp)
{
arr[j+1] = arr[j];
j--;
}
arr[j+1] = temp;
}
}

// Merge function merges the sorted runs
void merge(int arr[], int l, int m, int r)
{

// Original array is broken in two parts
// left and right array
int len1 = m - l + 1, len2 = r - m;
int left[len1], right[len2];
for (int i = 0; i < len1; i++)
left[i] = arr[l + i];
for (int i = 0; i < len2; i++)
right[i] = arr[m + 1 + i];

int i = 0;
int j = 0;
int k = l;

// After comparing, we
// merge those two array
// in larger sub array
while (i < len1 && j < len2)
{
if (left[i] <= right[j])
{
arr[k] = left[i];
i++;
}
else
{
arr[k] = right[j];
j++;
}
k++;
}

// Copy remaining elements of left, if any
while (i < len1)
{
arr[k] = left[i];
k++;
i++;
}

// Copy remaining element of right, if any
while (j < len2)
{
arr[k] = right[j];
k++;
j++;
}
}

// Iterative Timsort function to sort the
// array[0...n-1] (similar to merge sort)
void timSort(int arr[], int n)
{

// Sort individual subarrays of size RUN
for (int i = 0; i < n; i+=RUN) insertionSort(arr, i, min((i+RUN-1), (n-1)));

// Start merging from size RUN (or 32).
// It will merge
// to form size 64, then 128, 256
// and so on ....
for (int size = RUN; size < n; size = 2*size)
{

// pick starting point of
// left sub array. We
// are going to merge
// arr[left..left+size-1]
// and arr[left+size, left+2*size-1]
// After every merge, we
// increase left by 2*size
for (int left = 0; left < n;
left += 2*size)
{

// find ending point of
// left sub array
// mid+1 is starting point
// of right sub array
int mid = left + size - 1;
int right = min((left + 2*size - 1),
(n-1));

// merge sub array arr[left.....mid] &
// arr[mid+1....right]
if(mid < right)
merge(arr, left, mid, right);
}
}
}

// Utility function to print the Array
void printArray(int arr[], int n)
{
for (int i = 0; i < n; i++)
printf("%d ", arr[i]);
printf("\n");
}

// Driver program to test above function
int main()
{
int arr[] = {-2, 7, 15, -14, 0, 15, 0, 7, -7,
-4, -13, 5, 8, -14, 12};
int n = sizeof(arr)/sizeof(arr[0]);
printf("Given Array is\n");
printArray(arr, n);

// Function Call
timSort(arr, n);

printf("After Sorting Array is\n");
printArray(arr, n);
return 0;
}

时间复杂度

O(n)=O(nlog2n)O(n)=O(n\log_2{n})

空间复杂度

O(n)O(n)

· 3 min read

Timsort 是一种混合稳定的排序算法,源自合并排序和插入排序,旨在较好地处理真实世界中各种各样的数据。它使用了 Peter Mcllroy 的"乐观排序和信息理论上复杂性"中的技术,参见 第四届年度ACM-SIAM离散算法研讨会论文集,第467-474页,1993年。 它由 Tim Peters 在2002年实现,并应用于 Python编程语言。该算法通过查找已经排好序的数据子序列,在此基础上对剩余部分更有效地排序。 该算法通过不断地将特定子序列(称为一个 run )与现有的 run 合并,直到满足某些条件为止来达成的更有效的排序。 从 2.3 版本起,Timsort 一直是 Python 的标准排序算法。 它还被 Java SE7[4], Android platform[5], GNU Octave,[6] 谷歌浏览器,[7] 和 Swift[8] 用于对非原始类型的数组排序。

合并排序实现

  /* Merge-sort */
function merge(left, right) {
const arr = [];
while (left.length > 0 && right.length > 0) {
if (left[0] < right[0]) {
arr.push(left.shift());
} else {
arr.push(right.shift());
}
}

return [...arr, ...left, ...right];
}

function divSort(array) {
const half = array.length / 2;
if (array.length < 2) {
return array;
}

const left = array.splice(0, half);
return merge(divSort(left), divSort(array));
}

const testArray = [4, 8, 7, 2, 11, 1, 3];
console.log(divSort(testArray));

TimSort 和 quicksort

TimSort是高度优化的mergesort,它比旧的mergesort更稳定,更快。

与quicksort相比,它有两个优点:

  1. 对于几乎排序的数据序列(包括反向排序数据)来说,速度快得令人难以置信;
  2. 最坏的情况仍然是O(N * LOG(N))。 老实说,我不认为#1是一个优势,但它给我留下了深刻的印象。

这是QuickSort的优势

  1. QuickSort非常简单,即使是高度优化的实现,我们也可以在20行内写下它的pseduo代码;
  2. QuickSort在大多数情况下是最快的;
  3. 内存消耗为LOG(N)。

· 2 min read

http://datagenetics.com/blog/july22012/index.html

C++

#include <iostream>
#include <vector>
#include <string>
#include<algorithm>

using namespace std;

const int Floors = 25;
const int Eggs = 5;

// max{ fn{egg - 1, dropFloor} fn{egg, floor - dropFloor} }

// 一共egg个鸡蛋, floor层, 从dropFloor层扔, dropFloor 取值 1 - n
int drop(int egg, int floor) {
if (egg == 0 || floor == 0) {
printf("egg %d and floor %d: %d \n", egg, floor, 0);
return 0;
}

if (egg == 1) {
printf("egg %d and floor %d: %d \n", egg, floor, floor);
return floor;
}

if (floor == 1) {
printf("egg %d and floor %d: %d \n", egg, floor, 1);
return 1;
}

int minRes = INT_MAX;
for (int i = 1; i < floor; i++)
{
int curRes = max(drop(egg - 1, i - 1), drop(egg, floor - i));
if (minRes > curRes) {
minRes = curRes;
}
}

printf("egg %d and floor %d: %d \n", egg, floor, minRes + 1);
return minRes + 1;
}

int main()
{
int msg = drop(Eggs, Floors);

cout << msg << endl;
}

运行时间: 6.8512s

javascript

const Floors = 25;
const Eggs = 5;

// max{ fn{egg - 1, dropFloor} fn{egg, floor - dropFloor} }

// 一共egg个鸡蛋, floor层, 从dropFloor层扔
function drop(egg, floor) {
if (egg == 0 || floor == 0) {
return 0;
}

if (egg == 1) {
return floor;
}

if (floor == 1) {
return 1;
}

let minRes = Infinity;
for (let i = 1; i < floor; i++)
{
let curRes = Math.max(drop(egg - 1, i - 1), drop(egg, floor - i));
if (minRes > curRes) {
minRes = curRes;
}
}

return minRes + 1;
}

console.log(drop(Eggs, Floors));

运行时间: 6.022s

思路:F层E个鸡蛋 可以拆解成 假设从k层仍一个鸡蛋 Max{ k层E-1个鸡蛋, F-k层E个鸡蛋 }

k为最优解 可以用遍历的方式 k从 1 - F 层取值 Min{ (1 - F) 层扔一个鸡蛋 } 带入上面 递归计算。

· One min read
  • Mutex 是互斥锁。
  • 0值就是 unlocked 状态的 Mutex
  • Mutex 在第一次使用之后不能被复制

func(* Mutex) Lock

    func (m *Mutex) Lock()

func(* Mutex) Unlock

    func (m *Mutex) Unlock()

解锁已经解锁的Mutex, 运行时候报错

允许一个线程去锁,然后另外一个线程去解锁它

    package main

import (
"sync"
"time"
)

// Mutex lock 可以被别的线程 unlock --------
func main() {
var mu sync.Mutex
go func() {
mu.Lock()
time.Sleep(10 * time.Second)
mu.Unlock()
}()
time.Sleep(time.Second)
mu.Unlock()
select {}
}

· One min read

Decorators make it possible to annotate and modify classes and properties at design time.

A decorator is:

  • an expression
  • that evaluates to a function
  • that takes the target, name, and decorator descriptor as arguments
  • and optionally returns a decorator descriptor to install on the target object

A decorator precedes the syntax that defines a property:

class Person {
@readonly
name() { return `${this.first} ${this.last}` }
}

Now, before installing the descriptor onto Person.prototype, the engine first invokes the decorator:

let description = {
type: 'method',
initializer: () => specifiedFunction,
enumerable: false,
configurable: true,
writable: true
};

description = readonly(Person.prototype, 'name', description) || description;
defineDecoratedProperty(Person.prototype, 'name', description);

function defineDecoratedProperty(target, { initializer, enumerable, configurable, writable }) {
Object.defineProperty(target, { value: initializer(), enumerable, configurable, writable });
}

The has an opportunity to intercede before the relevant defineProperty actually occurs.

· One min read

read tree files in order:f1.txt, f2.txt, f3.txt

fs.readFile: asynchronous return file data

read.js

const fs = require('fs');

function getFileResult(path) {
return new Promise((resolve, reject) => {
fs.readFile(path, (err, data) => {
if(err) {
reject(err);
}
resolve(data);
})
})
}

function* read() {
yield getFileResult('./f1.txt');
yield getFileResult('./f2.txt');
yield getFileResult('./f3.txt');
}

// Manual Execution
// const g = read();
// g.next().value.then(res => {
// console.log('ressss1', res.toString());
// })

// g.next().value.then(res => {
// console.log('resss2', res.toString());
// })

// Auto Execution
function autoRun(gen) {
const g = gen();
let arr = [];
function run(gObject) {
const {
value,
done
} = gObject.next();
console.log('value', value);

if(done) {
console.log('arr', arr);
return arr;
}
value.then(res => {
console.log('res', res);
arr.push(res.toString());
run(gObject);
})
}
run(g);
}

autoRun(read);

f1.txt

11111111

f2.txt and f3.txt as same as f1.txt

· 2 min read

 软键盘唤起后,页面的 fixed 元素将失效(ios认为用户更希望的是元素随着滚动而移动,也就是变成了 absolute 定位),既然变成了absolute,所以当页面超过一屏且滚动时,失效的 fixed 元素就会跟随滚动了。 不仅限于 type=text 的输入框,凡是软键盘(比如时间日期选择、select 选择等等)被唤起,都会遇到同样地问题。

如何解决

  1. 既然会变成absolute,索性直接使用absolute算了。
  2. 不让页面滚动,而是让主体部分自己滚动

ios下软键盘预测输入未完成之前点击完成,收起软键盘,软键盘隐藏之后,再次点击input框,点击事件触发,但是软键盘不再弹出问题....

如何解决

这个问题暂时没有找到解决方案

· 4 min read

组件如何实现数据双向绑定?

  <template>
<div :class="wrapClasses">
<template v-if="type !== 'textarea'">
<div :class="[prefixCls + '-group-prepend']" v-if="prepend" v-show="slotReady"><slot name="prepend"></slot></div>
<i class="ivu-icon" :class="['ivu-icon-ios-close-circle', prefixCls + '-icon', prefixCls + '-icon-clear' , prefixCls + '-icon-normal']" v-if="clearable && currentValue" @click="handleClear"></i>
<i class="ivu-icon" :class="['ivu-icon-' + icon, prefixCls + '-icon', prefixCls + '-icon-normal']" v-else-if="icon" @click="handleIconClick"></i>
<i class="ivu-icon ivu-icon-ios-search" :class="[prefixCls + '-icon', prefixCls + '-icon-normal', prefixCls + '-search-icon']" v-else-if="search && enterButton === false" @click="handleSearch"></i>
<span class="ivu-input-suffix" v-else-if="showSuffix"><slot name="suffix"><i class="ivu-icon" :class="['ivu-icon-' + suffix]" v-if="suffix"></i></slot></span>
<transition name="fade">
<i class="ivu-icon ivu-icon-ios-loading ivu-load-loop" :class="[prefixCls + '-icon', prefixCls + '-icon-validate']" v-if="!icon"></i>
</transition>
<input
:id="elementId"
:autocomplete="autocomplete"
:spellcheck="spellcheck"
ref="input"
:type="type"
:class="inputClasses"
:placeholder="placeholder"
:disabled="disabled"
:maxlength="maxlength"
:readonly="readonly"
:name="name"
:value="currentValue"
:number="number"
:autofocus="autofocus"
@keyup.enter="handleEnter"
@keyup="handleKeyup"
@keypress="handleKeypress"
@keydown="handleKeydown"
@focus="handleFocus"
@blur="handleBlur"
@input="handleInput"
@change="handleChange">
<div :class="[prefixCls + '-group-append']" v-if="append" v-show="slotReady"><slot name="append"></slot></div>
<div :class="[prefixCls + '-group-append', prefixCls + '-search']" v-else-if="search && enterButton" @click="handleSearch">
<i class="ivu-icon ivu-icon-ios-search" v-if="enterButton === true"></i>
<template v-else>{{ enterButton }}</template>
</div>
<span class="ivu-input-prefix" v-else-if="showPrefix"><slot name="prefix"><i class="ivu-icon" :class="['ivu-icon-' + prefix]" v-if="prefix"></i></slot></span>
</template>
<textarea
v-else
:id="elementId"
:wrap="wrap"
:autocomplete="autocomplete"
:spellcheck="spellcheck"
ref="textarea"
:class="textareaClasses"
:style="textareaStyles"
:placeholder="placeholder"
:disabled="disabled"
:rows="rows"
:maxlength="maxlength"
:readonly="readonly"
:name="name"
:value="currentValue"
:autofocus="autofocus"
@keyup.enter="handleEnter"
@keyup="handleKeyup"
@keypress="handleKeypress"
@keydown="handleKeydown"
@focus="handleFocus"
@blur="handleBlur"
@input="handleInput">
</textarea>
</div>
</template>
<script>
import { oneOf, findComponentUpward } from '../../utils/assist';
import calcTextareaHeight from '../../utils/calcTextareaHeight';
import Emitter from '../../mixins/emitter';
const prefixCls = 'ivu-input';
export default {
name: 'Input',
mixins: [ Emitter ],
props: {
type: {
validator (value) {
return oneOf(value, ['text', 'textarea', 'password', 'url', 'email', 'date']);
},
default: 'text'
},
value: {
type: [String, Number],
default: ''
},
size: {
validator (value) {
return oneOf(value, ['small', 'large', 'default']);
},
default () {
return !this.$IVIEW || this.$IVIEW.size === '' ? 'default' : this.$IVIEW.size;
}
},
placeholder: {
type: String,
default: ''
},
maxlength: {
type: Number
},
disabled: {
type: Boolean,
default: false
},
icon: String,
autosize: {
type: [Boolean, Object],
default: false
},
rows: {
type: Number,
default: 2
},
readonly: {
type: Boolean,
default: false
},
name: {
type: String
},
number: {
type: Boolean,
default: false
},
autofocus: {
type: Boolean,
default: false
},
spellcheck: {
type: Boolean,
default: false
},
autocomplete: {
validator (value) {
return oneOf(value, ['on', 'off']);
},
default: 'off'
},
clearable: {
type: Boolean,
default: false
},
elementId: {
type: String
},
wrap: {
validator (value) {
return oneOf(value, ['hard', 'soft']);
},
default: 'soft'
},
prefix: {
type: String,
default: ''
},
suffix: {
type: String,
default: ''
},
search: {
type: Boolean,
default: false
},
enterButton: {
type: [Boolean, String],
default: false
}
},
data () {
return {
currentValue: this.value,
prefixCls: prefixCls,
prepend: true,
append: true,
slotReady: false,
textareaStyles: {},
showPrefix: false,
showSuffix: false
};
},
computed: {
wrapClasses () {
return [
`${prefixCls}-wrapper`,
{
[`${prefixCls}-wrapper-${this.size}`]: !!this.size,
[`${prefixCls}-type`]: this.type,
[`${prefixCls}-group`]: this.prepend || this.append || (this.search && this.enterButton),
[`${prefixCls}-group-${this.size}`]: (this.prepend || this.append || (this.search && this.enterButton)) && !!this.size,
[`${prefixCls}-group-with-prepend`]: this.prepend,
[`${prefixCls}-group-with-append`]: this.append || (this.search && this.enterButton),
[`${prefixCls}-hide-icon`]: this.append, // #554
[`${prefixCls}-with-search`]: (this.search && this.enterButton)
}
];
},
inputClasses () {
return [
`${prefixCls}`,
{
[`${prefixCls}-${this.size}`]: !!this.size,
[`${prefixCls}-disabled`]: this.disabled,
[`${prefixCls}-with-prefix`]: this.showPrefix,
[`${prefixCls}-with-suffix`]: this.showSuffix || (this.search && this.enterButton === false)
}
];
},
textareaClasses () {
return [
`${prefixCls}`,
{
[`${prefixCls}-disabled`]: this.disabled
}
];
}
},
methods: {
handleEnter (event) {
this.$emit('on-enter', event);
if (this.search) this.$emit('on-search', this.currentValue);
},
handleKeydown (event) {
this.$emit('on-keydown', event);
},
handleKeypress(event) {
this.$emit('on-keypress', event);
},
handleKeyup (event) {
this.$emit('on-keyup', event);
},
handleIconClick (event) {
this.$emit('on-click', event);
},
handleFocus (event) {
this.$emit('on-focus', event);
},
handleBlur (event) {
this.$emit('on-blur', event);
if (!findComponentUpward(this, ['DatePicker', 'TimePicker', 'Cascader', 'Search'])) {
this.dispatch('FormItem', 'on-form-blur', this.currentValue);
}
},
handleInput (event) {
let value = event.target.value;
if (this.number && value !== '') value = Number.isNaN(Number(value)) ? value : Number(value);
this.$emit('input', value);
this.setCurrentValue(value);
this.$emit('on-change', event);
},
handleChange (event) {
this.$emit('on-input-change', event);
},
setCurrentValue (value) {
if (value === this.currentValue) return;
this.$nextTick(() => {
this.resizeTextarea();
});
this.currentValue = value;
if (!findComponentUpward(this, ['DatePicker', 'TimePicker', 'Cascader', 'Search'])) {
this.dispatch('FormItem', 'on-form-change', value);
}
},
resizeTextarea () {
const autosize = this.autosize;
if (!autosize || this.type !== 'textarea') {
return false;
}
const minRows = autosize.minRows;
const maxRows = autosize.maxRows;
this.textareaStyles = calcTextareaHeight(this.$refs.textarea, minRows, maxRows);
},
focus () {
if (this.type === 'textarea') {
this.$refs.textarea.focus();
} else {
this.$refs.input.focus();
}
},
blur () {
if (this.type === 'textarea') {
this.$refs.textarea.blur();
} else {
this.$refs.input.blur();
}
},
handleClear () {
const e = { target: { value: '' } };
this.$emit('input', '');
this.setCurrentValue('');
this.$emit('on-change', e);
},
handleSearch () {
if (this.disabled) return false;
this.$refs.input.focus();
this.$emit('on-search', this.currentValue);
}
},
watch: {
value (val) {
this.setCurrentValue(val);
}
},
mounted () {
if (this.type !== 'textarea') {
this.prepend = this.$slots.prepend !== undefined;
this.append = this.$slots.append !== undefined;
this.showPrefix = this.prefix !== '' || this.$slots.prefix !== undefined;
this.showSuffix = this.suffix !== '' || this.$slots.suffix !== undefined;
} else {
this.prepend = false;
this.append = false;
}
this.slotReady = true;
this.resizeTextarea();
}
};
</script>

· 2 min read

输出(Emits)符合所提供的匹配模式(glob)或者匹配模式的数组(array of globs)的文件。 将返回一个 Vinyl files 的 stream 它可以被 piped 到别的插件中。

gulp是一个有关Stream(数据流)的构建系统,gulp本身使用了Node的Stream.

gulp.src("app.js").pipe(babel())

这里src("app.js")作为源,作为输入流到babel()去进行处理。 这种流的构建方式给我们带来了方便。

而这个stream 是 Vinyl files。

Vinyl is a very simple metadata object that describes a file. 翻译:Vinyl 是一种用来描述文件的非常简便的中介对象。

常用的几个plugin:

  • browserify
  • vinyl-source-stream
  • rename
  • gulp-babel

这里主要介绍一下browserify和vinyl-source-stream

browserify

Browserify lets you require('modules') in the browser by bundling up all of your dependencies.

Browserify 通过打包所有的依赖,让你们用require('modules')的方式在浏览器中获取模块。

vinyl-source-stream

Take, for example, browserify. There are the gulp-browserify and gulpify plugins, which you can use in combination with gulp to get browserify working in your build. Unfortunately, these plugins come with additional overhead: an extra GitHub repository, npm module, maintainer, tests, semantics, etc.

使用vinyl-source-stream 能够很快的帮我们处理例如browserify这些插件的额外的头,例如an extra GitHub repository

自己配置的一个简单的gulp的配置文件如下:

var gulp = require("gulp");
var babel = require("gulp-babel");
var rename = require("gulp-rename");
var browserify = require("browserify");
var source = require('vinyl-source-stream')

gulp.task("babel", function (cb) {
return gulp.src("app.js")
.pipe(babel())
.pipe(rename('main.js'))
.pipe(gulp.dest("./"));
cb(err);
});

gulp.task('browserify', function() {
return browserify({
entries: 'main.js',
debug: true
})
.bundle()
.pipe(source('main.js'))
.pipe(gulp.dest('dist'));
})

gulp.task('default', ['babel', 'browserify'])