DahuX

DahuX 查看完整档案

填写现居城市  |  填写毕业院校  |  填写所在公司/组织填写个人主网站
编辑
_ | |__ _ _ __ _ | '_ \| | | |/ _` | | |_) | |_| | (_| | |_.__/ \__,_|\__, | |___/ 该用户太懒什么也没留下

个人动态

DahuX 赞了文章 · 2019-07-20

通过PHP与Python代码对比浅析语法差异

一、背景

人工智能这几年一直都比较火,笔者一直想去学习一番;因为一直是从事PHP开发工作,对于Python接触并不算多,总是在关键时候面临着基础不牢,地动山摇的尴尬,比如在遇到稍微深入些的问题时候就容易卡壳,于是准备从Python入门从头学起;

笔者觉得应该有不少人同样熟悉PHP或者Python语言,对另外一个门语言并不是太熟悉,有想法学习另外一门语言,希望通过这篇文章能够对大家有一点帮助。

二、知识点

最近在完成一个小作业,题目要求:通过Python代码实现,让用户输入用户名密码,认证成功后显示欢迎信息,输错三次后退出程序。

在这篇文章当中,会通过这个小作业来总结和分析PHP与Python的语法区别,主要涉及到以下几个知识点:

  1. 代码整体风格
  2. 变量命名规范
  3. 常量命名规范
  4. 注释方式
  5. 数据类型
  6. 输入输出
  7. if语句使用
  8. while循环

三、Python语法

在Python中需要严格遵守空格缩进,否则会报错;在每行代码后面不需要使用;,结构体的条件不需要使用(),执行体里面则不需要{}

3.1 代码示例

# -*- coding: utf-8 -*-
n = 0

while n < 3:
    #累计次数,用于循环条件
    n = n + 1
    #定义账号和密码
    uname = 'tangqingsong'
    pwd = '123123'
    #接收参数
    username = input('请输入用户名:')
    password = input('请输入密码:')

    #判断用户输入的账号和密码是否正确,正确将提示成功,并且退出循环体
    if uname == username and pwd == password:
        print ('恭喜你,登陆成功~')
        break
    #三次机会用完的时候,提示错误次数,并告知即将退出
    elif n == 3:
        print('已错误', n, '次,即将退出...')
    #如果在三次以内,提示还剩下几次机会
    else:
        print('抱歉,账号或密码不正确,你还有', 3 - n, '次机会')

3.2 基本语法

下面从基本语法、数据类型、IF控制、while循环几个方面来聊聊Python代码中的一些规范

3.2.1 基础语法

变量: 在Python中变量以数字 字母 下划线组成,不能以数字开头,不能是python中的关键字,比如 whileifelifelsebreakcontinue等,同样推荐使用驼峰命名和下划线命名两种规范命名格式

常量: 在Python中常量和变量在定义的方式上没有太大的区别,知识Python中约定俗成的使用全大写定义而已

注释: 在Python中,注释可以通过#来注释某行代码,也可以通过'''注释某段代码,比如'''注释内容'''

3.2.2 数据类型

在Python中,可以通过type(变量名)来获取变量的数据类型,经常使用到的数据类型有:布尔、整型、浮点型、字符串等;在布尔型中 真/True/1 假/False/0,非0的数字都是True;

在字符串中可以通过单引号和双引号两种方式定义,比如

a = '字符串'
b = "字符串"

也可以使用

a = '''可以换行
    这里有换行
  这里也有换行
的字符串
'''
#或者三个双引号

b = """可以换行
    这里有换行
  这里也有换行
的字符串"""

来定义一大段字符串;字符串可以使用字符串 + 字符串的方式进行拼接,也可以使用 字符串 * 数字,将字符串重复凭借,比如 'abc' * 2,name得出的字符串便是abcabc

3.2.3 数据类型

在整型和浮点数据类型中加减乘除没有什么太特别,同样是使用+-*/这四个符号,使用%可以的出余数;Python中有几个特殊的运算符,比如可以使用//进行整除,得出的结果不会有小数,如下代码所示:

a = 10 // 3 

# 得到的结果是 3

也可以使用**可以得到乘方,如下代码所示;

b = 2 ** 2 

# 得到的结果是 8

3.2.4 输入输出

输入输出:在Python中可以使用print关键字对变量进行打印输出,可以通过 input接收用户在终端中传递的参数,例如

inp = input('用户输入的时候看到的提示 :')

通过input方式接收的所有内容都是字符串类型,如果需要用来做运算需要对接收的变量进行类型转换;比如

a = int(变量名)

可以将变量转换成整型,也可以通过

f = float(变量名)

转换成浮点型;

3.3 IF控制

在Python中if语句使用的时候条件不需要使用()包括,执行体在也不需要使用{}包括,但执行体必须严格遵守缩进如下代码所示

# if a >3 and b==2:
    缩进 满足条件1之后要做的事情
  elif a>3 and b==3:
    缩进 不满足条件1但满足条件2之后要做的事情
  else:
    缩进 上面的条件都不满足要做的事情

3.4 while循环

在Python中使用while方法与PHP类似,如下为伪代码所示

while a == b:
    循环执行的代码

可以使用关键词break退出循环,也可以使用continue跳过循环过程中的某一步,如下代码所示

i = 1
while i < 10:   
    i += 1
    # 非双数时跳过输出
    if i%2 > 0:     
        continue
    # 输出双数2、4、6、8
    print i         
    # 当条件为8时候退出循环
    if i == 8:
        break

四、PHP语法

在PHP中并不需要严格遵守空格缩进,但是和Python相对应的是在每行代码后面通常需要使用;结尾,结构体的条件也需要使用(),执行体里面同样需要{}

4.1 代码示例

<?php

$n = 0;

while ($n < 3) {
    #累计次数,用于循环条件
    $n = $n + 1;
    #定义账号和密码
    $uname = 'tangqingsong';
    $pwd = '123123';
    #接收参数
    fwrite(STDOUT, '请输入用户名:');
    $username = trim(fgets(STDIN));
    fwrite(STDOUT, '请输入密码:');
    $password = trim(fgets(STDIN));

    #判断用户输入的账号和密码是否正确,正确将提示成功,并且退出循环体
    if ($uname == $username and $pwd == $password) {
        print_r('恭喜你,登陆成功~');
        break;
        #三次机会用完的时候,提示错误次数,并告知即将退出
    } elseif ($n == 3) {
        print_r("已错误{$n}次,即将退出...");
    } else {
        #如果在三次以内,提示还剩下几次机会
        $j = 3 - $n;
        print_r("抱歉,账号或密码不正确,你还有{$j}次机会");
    }
}

4.2 基本语法

下面从基本语法、数据类型、IF控制、while循环几个方面来聊聊PHP代码中的一些规范

4.2.1 基础语法

变量: 在PHP中变量以数字 字母 下划线组成,必须以$符号开头,且第一个字符不能以数字开头,在PHP中因为变量都是以$开头,所以基本上没有关键字的说法,但是写代码的时候尽量不要覆盖系统变量即可,同样推荐使用驼峰命名和下划线命名两种规范命名格式

常量: 在PHP中常量同样约定俗成的使用全大写定义而已,在定义的方式有专门的定义格式,比如定义DAXIA的值为tangqingsong时候,代码如下所示

const   DAXIA = 'tangqingsong';

注释: 在PHP中,注释可以通过#来注释某行代码,也可以使用//定义行代码,也可以通过/****/注释某段代码,如下代码所示

#这是行注释

//这是行注释,一般习惯是使用此种方式

/**
 *  块注释,一般在自定义函数和类方法的时候使用
 */

4.2.2 数据类型

在PHP中,可以通过var_dump(变量名)同时打印变量类型和值,经常使用到的数据类型有:布尔、整型、浮点型、字符串等;同样在布尔型中 真/True/1 假/False/0,非0的数字都是True;

在字符串中可以通过单引号和双引号两种方式定义,单引号中不能放变量,但是双引号是可以的,如下代码所示

$n = 123;

a = '字符串';
b = "字符串{$n}";

当大家定义块文本内容的时候,也可以使用定界符方式,如下代码所示

$a = <<<EF

这里是大文本内容,可以写任意文本,EF是自定义的,大家也可以把EF写成DAXIA,但是必须前后对应,后面的必须定格,后面一个“EF”不能用空格之类的字符;

EF;

字符串可以使用符号 . 进行拼接,如下代码所示:

$name = 'daxia' . 'tangqingsong';

4.2.3 数据类型

在PHP中整型和浮点数据类型中加减乘除没有什么太特别,同样是使用+-*/这四个符号,使用%可以的出余数;

4.2.4 输入输出

输入输出:在PHP中可以使用print_r关键字对变量进行打印输出,在接收标准输入方面稍微麻烦,需要先通过fwrite接收用户在终端中传递的参数,然后再通过fgets函数将变量值取出来,还需要通过trim将后面的空格过滤,例如

    fwrite(STDOUT, '请输入用户名:');   
    $username = trim(fgets(STDIN));

通过上面代码方式接收的所有内容都是字符串类型,但是PHP是弱类型语言,并不强大变量的数据类型,所以大部分情况无需进行类型转换,如果需要用到类型转换方法和Python大体类型,如下代码所示

a = intval(变量名)

可以将变量转换成整型,也可以通过

f = floatval(变量名)

转换成浮点型;

4.3 IF控制

if条件:在PHP中if语句的使用方法如下代码所示

<?php
if (a >3 and b==2){
    满足条件1之后要做的事情
} elseif (a>3 and b==3){
    不满足条件1但满足条件2之后要做的事情
} else {
    上面的条件都不满足要做的事情
}

4.4 while循环

while循环:在PHP中while的条件必须使用()包括,执行体在也必须使用{}包括,执行体不要求严格的缩进,但是为了美观,一般都会缩进,如下为伪代码所示

<?php
while ($a == $b){
    //循环执行的代码
}

可以使用关键词break退出循环,也可以使用continue跳过循环过程中的某一步,如下代码所示

<?php

$i = 1;
while ($i < 10) {
    $i += 1;
    //非双数时跳过输出
    if ($i % 2 > 0) {
        continue;
    }
    
    //输出双数2、4、6、8
    print_r($i);
    
    //当条件为8时候退出循环
    if ($i == 8) {
        break;
    }
}

作者:汤青松

微信:songboy8888

更新日期:2019-07-09

查看原文

赞 26 收藏 13 评论 2

DahuX 赞了文章 · 2017-08-05

这两个小工具,真是推荐了还想推荐。

其实是两款截图工具,可能你会说这东西还用推荐么,QQ有、微信用,不用下载了吧,别急,往下看。

Screenpresso

大家都知道,要想做一个高逼格的截图,不在于截,而在于截图后的那几下编辑,看看 Screenpresso 表现。

更好看的箭头和文字

N中箭头、直接用系统字体

重点突出功能

半透明的黄色蒙版让你轻松突出图片中重要的部分。

alt

好看的数字样式

这个数字更好玩,还能自动识别,第一次是1,第二次就自动是2了。

alt

各种框框圈圈应有尽有

alt

还有马赛克

比如你的图片需要隐藏个手机号啥的,再也不用铅笔工具了,马赛克多闷骚啊。

alt

扩大镜功能

比如你想给客户突出几个词,弄个扩大镜,一下弄蒙他们。

alt

括号功能

这个没见过吧,突出图片某一部分的又一个好玩的功能。

alt

当然

其实还有很多,比如还能录屏,还能保持最近的40次截屏,操作也很简单,算一个能不停给你惊喜的工具啦。

GifCam

这个小工具都不用安装,完全绿色,是录制动态gif的工具。

操作很简单,见下图

alt

不相信?看看下面用gifcam生成的gif图,你会喜欢的。

alt

你喜欢么

话说阿北也算一个老江湖了,但是面对这两个小神器,真的太喜欢了,有种工具叫做不由自主的去使用,说的就是它们。

完事了。


阿北哥ya
专注于Yii2和小程序视频教学服务

查看原文

赞 73 收藏 556 评论 33

DahuX 赞了文章 · 2017-07-27

10个JavaScript难点

译者按:能够读懂这篇博客的JavaScript开发者,运气不会太差...

原文: 10 JavaScript concepts every Node.js programmer must master

译者: Fundebug

为了保证可读性,本文采用意译而非直译,并且对示例代码进行了大量修改。另外,本文版权归原作者所有,翻译仅用于学习。

1. 立即执行函数

立即执行函数,即Immediately Invoked Function Expression (IIFE),正如它的名字,就是创建函数的同时立即执行。它没有绑定任何事件,也无需等待任何异步操作:

(function() {
     // 代码
     // ...
})();

function(){…}是一个匿名函数,包围它的一对括号将其转换为一个表达式,紧跟其后的一对括号调用了这个函数。立即执行函数也可以理解为立即调用一个匿名函数。立即执行函数最常见的应用场景就是:将var变量的作用域限制于你们函数内,这样可以避免命名冲突。

2. 闭包

对于闭包(closure),当外部函数返回之后,内部函数依然可以访问外部函数的变量。

function f1()
{
    var N = 0; // N是f1函数的局部变量
    
    function f2() // f2是f1函数的内部函数,是闭包
    {
        N += 1; // 内部函数f2中使用了外部函数f1中的变量N
        console.log(N);
    }

    return f2;
}

var result = f1();

result(); // 输出1
result(); // 输出2
result(); // 输出3

代码中,外部函数f1只执行了一次,变量N设为0,并将内部函数f2赋值给了变量result。由于外部函数f1已经执行完毕,其内部变量N应该在内存中被清除,然而事实并不是这样:我们每次调用result的时候,发现变量N一直在内存中,并且在累加。为什么呢?这就是闭包的神奇之处了!

3. 使用闭包定义私有变量

通常,JavaScript开发者使用下划线作为私有变量的前缀。但是实际上,这些变量依然可以被访问和修改,并非真正的私有变量。这时,使用闭包可以定义真正的私有变量:

function Product() {

    var name;

    this.setName = function(value) {
        name = value;
    };

    this.getName = function() {
        return name;
    };
}

var p = new Product();
p.setName("Fundebug");

console.log(p.name); // 输出undefined
console.log(p.getName()); // 输出Fundebug

代码中,对象p的的name属性为私有属性,使用p.name不能直接访问。

4. prototype

每个JavaScript构造函数都有一个prototype属性,用于设置所有实例对象需要共享的属性和方法。prototype属性不能列举。JavaScript仅支持通过prototype属性进行继承属性和方法。

function Rectangle(x, y)
{
    this._length = x;
    this._breadth = y;
}

Rectangle.prototype.getDimensions = function()
{
    return {
        length: this._length,
        breadth: this._breadth
    };
};

var x = new Rectangle(3, 4);
var y = new Rectangle(4, 3);

console.log(x.getDimensions()); // { length: 3, breadth: 4 }
console.log(y.getDimensions()); // { length: 4, breadth: 3 }

代码中,xy都是构造函数Rectangle创建的对象实例,它们通过prototype继承了getDimensions方法。

5. 模块化

JavaScript并非模块化编程语言,至少ES6落地之前都不是。然而对于一个复杂的Web应用,模块化编程是一个最基本的要求。这时,可以使用立即执行函数来实现模块化,正如很多JS库比如jQuery以及我们Fundebug都是这样实现的。

var module = (function() {
    var N = 5;

    function print(x) {
        console.log("The result is: " + x);
    }

    function add(a) {
        var x = a + N;
        print(x);
    }

    return {
        description: "This is description",
        add: add
    };
})();


console.log(module.description); // 输出"this is description" 

module.add(5); // 输出“The result is: 10”

所谓模块化,就是根据需要控制模块内属性与方法的可访问性,即私有或者公开。在代码中,module为一个独立的模块,N为其私有属性,print为其私有方法,decription为其公有属性,add为其共有方法。

6. 变量提升

JavaScript会将所有变量和函数声明移动到它的作用域的最前面,这就是所谓的变量提升(Hoisting)。也就是说,无论你在什么地方声明变量和函数,解释器都会将它们移动到作用域的最前面。因此我们可以先使用变量和函数,而后声明它们。

但是,仅仅是变量声明被提升了,而变量赋值不会被提升。如果你不明白这一点,有时则会出错:

console.log(y);  // 输出undefined

y = 2; // 初始化y

上面的代码等价于下面的代码:

var y;  // 声明y

console.log(y);  // 输出undefined

y = 2; // 初始化y

为了避免BUG,开发者应该在每个作用域开始时声明变量和函数。

7. 柯里化

柯里化,即Currying,可以是函数变得更加灵活。我们可以一次性传入多个参数调用它;也可以只传入一部分参数来调用它,让它返回一个函数去处理剩下的参数。

var add = function(x) {
    return function(y) {
        return x + y;
    };
};

console.log(add(1)(1)); // 输出2

var add1 = add(1);
console.log(add1(1)); // 输出2

var add10 = add(10);
console.log(add10(1)); // 输出11

代码中,我们可以一次性传入2个1作为参数add(1)(1),也可以传入1个参数之后获取add1add10函数,这样使用起来非常灵活。

8. apply, call与bind方法

JavaScript开发者有必要理解applycallbind方法的不同点。它们的共同点是第一个参数都是this,即函数运行时依赖的上下文。

三者之中,call方法是最简单的,它等价于指定this值调用函数:

var user = {
    name: "Rahul Mhatre",
    whatIsYourName: function() {
        console.log(this.name);
    }
};

user.whatIsYourName(); // 输出"Rahul Mhatre",

var user2 = {
    name: "Neha Sampat"
};

user.whatIsYourName.call(user2); // 输出"Neha Sampat"

apply方法与call方法类似。两者唯一的不同点在于,apply方法使用数组指定参数,而call方法每个参数单独需要指定:

  • apply(thisArg, [argsArray])
  • call(thisArg, arg1, arg2, …)
var user = {
    greet: "Hello!",
    greetUser: function(userName) {
        console.log(this.greet + " " + userName);
    }
};

var greet1 = {
    greet: "Hola"
};

user.greetUser.call(greet1, "Rahul"); // 输出"Hola Rahul"
user.greetUser.apply(greet1, ["Rahul"]); // 输出"Hola Rahul"

使用bind方法,可以为函数绑定this值,然后作为一个新的函数返回:

var user = {
     greet: "Hello!",
     greetUser: function(userName) {
     console.log(this.greet + " " + userName);
     }
};

var greetHola = user.greetUser.bind({greet: "Hola"});
var greetBonjour = user.greetUser.bind({greet: "Bonjour"});

greetHola("Rahul") // 输出"Hola Rahul"
greetBonjour("Rahul") // 输出"Bonjour Rahul"

9. Memoization

Memoization用于优化比较耗时的计算,通过将计算结果缓存到内存中,这样对于同样的输入值,下次只需要中内存中读取结果。

function memoizeFunction(func)
{
    var cache = {};
    return function()
    {
        var key = arguments[0];
        if (cache[key])
        {
            return cache[key];
        }
        else
        {
            var val = func.apply(this, arguments);
            cache[key] = val;
            return val;
        }
    };
}


var fibonacci = memoizeFunction(function(n)
{
    return (n === 0 || n === 1) ? n : fibonacci(n - 1) + fibonacci(n - 2);
});

console.log(fibonacci(100)); // 输出354224848179262000000
console.log(fibonacci(100)); // 输出354224848179262000000

代码中,第2次计算fibonacci(100)则只需要在内存中直接读取结果。

10. 函数重载

所谓函数重载(method overloading),就是函数名称一样,但是输入输出不一样。或者说,允许某个函数有各种不同输入,根据不同的输入,返回不同的结果。凭直觉,函数重载可以通过if...else或者switch实现,这就不去管它了。jQuery之父John Resig提出了一个非常巧(bian)妙(tai)的方法,利用了闭包。

从效果上来说,people对象的find方法允许3种不同的输入: 0个参数时,返回所有人名;1个参数时,根据firstName查找人名并返回;2个参数时,根据完整的名称查找人名并返回。

难点在于,people.find只能绑定一个函数,那它为何可以处理3种不同的输入呢?它不可能同时绑定3个函数find0,find1find2啊!这里的关键在于old属性。

addMethod函数的调用顺序可知,people.find最终绑定的是find2函数。然而,在绑定find2时,oldfind1;同理,绑定find1时,oldfind0。3个函数find0,find1find2就这样通过闭包链接起来了。

根据addMethod的逻辑,当f.lengtharguments.length不匹配时,就会去调用old,直到匹配为止。

function addMethod(object, name, f)
{  
    var old = object[name];  
    object[name] = function()
    {
        // f.length为函数定义时的参数个数
        // arguments.length为函数调用时的参数个数    
        if (f.length === arguments.length)
        {  
            return f.apply(this, arguments);    
        }
        else if (typeof old === "function")
        {
            return old.apply(this, arguments);    
        }  
    };
}


// 不传参数时,返回所有name
function find0()
{  
    return this.names;
}


// 传一个参数时,返回firstName匹配的name
function find1(firstName)
{  
    var result = [];  
    for (var i = 0; i < this.names.length; i++)
    {    
        if (this.names[i].indexOf(firstName) === 0)
        {      
            result.push(this.names[i]);    
        }  
    }  
    return result;
}


// 传两个参数时,返回firstName和lastName都匹配的name
function find2(firstName, lastName)
{ 
    var result = [];  
    for (var i = 0; i < this.names.length; i++)
    {    
        if (this.names[i] === (firstName + " " + lastName))
        {      
            result.push(this.names[i]);    
        }  
    }  
    return result;
}


var people = {  
    names: ["Dean Edwards", "Alex Russell", "Dean Tom"]
};


addMethod(people, "find", find0);
addMethod(people, "find", find1);
addMethod(people, "find", find2);


console.log(people.find()); // 输出["Dean Edwards", "Alex Russell", "Dean Tom"]
console.log(people.find("Dean")); // 输出["Dean Edwards", "Dean Tom"]
console.log(people.find("Dean", "Edwards")); // 输出["Dean Edwards"]

参考链接

关于Fundebug

Fundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了6亿+错误事件,得到了Google、360、金山软件等众多知名用户的认可。欢迎免费试用!

图片描述

版权声明

转载时请注明作者Fundebug以及本文地址:
https://blog.fundebug.com/2017/07/17/10-javascript-difficulties/

查看原文

赞 41 收藏 254 评论 15

DahuX 赞了文章 · 2017-07-27

Git各种错误操作撤销的方法

概述

  • 在平时工作中使用git难免会提交一些错误的文件到git库里,这时候,撤销吧,怕把正确的文件删除了,不撤销重新改又很麻烦,下面,我就从提交的三个阶段,来讲解如何撤销错误的操作。

Git Add了一个错误文件

解决方法

  • 这种情况一般发生在新创建的项目,执行命令:

    git add .

命令执行完后发现增加了错误的文件,比如Pycham自动生成的.idea文件夹。比如下图:

这时候,我想撤销add .idea这个操作,可以这么做:

    
git reset  #撤销指定的文件
git reset #撤销所有的文件

执行完这个命令后,效果如下:

可以看到.idea这个目录变成了Untracked了。完美解决。
如果你在执行的时候遇到如下的错误:

fatal: Failed to resolve 'HEAD' as a valid ref.

如果遇到这个错误,就说明你的本地git仓库从来没有执行过git commit操作,导致HEAD指针不存在。这时候你可以通过如下的命令撤销操作:


git rm --cached .   #删除文件
git rm -r --cached . #删除文件和目录

如何避免

  • .gitignore: 把不需要提交的文件增加到这个文件
  • git add : 增加指定的文件,少用点号

Git Commit了一个错误文件

举例

我现在有个文件的状态如下:

执行git diff blog-test.py后结果如下:

可以看到我增加了一行,现在把文件提交到本地仓库:

可以看到,本地以及没有需要提交的文件了。这时候,我发现,这个修改是错误的,我需要撤销这次commit,我该怎么做了?

只撤销commit操作,保留文件

执行命令如下:

git reset HEAD~1

执行完效果如下:

可以看到,commit被撤销了,但是修改的部分还保留着。完美解决。不信看git log

撤销commit操作,删除变化

执行命令如下:

git reset --hard HEAD~1

执行完后效果如下:

可以看到,我增加的那一行已经没有了,git log中也没有了那次的提交记录:

完美

如何避免

  • git status: 查看是否有不需要的文件被add进来
  • git diff: 查看文件的变化部分,是否是想提交的

查看更多

Git如何取消最新一次的commit

如何删除分支

好,现在有个很严重的问题,我的分支里代码不用了,现在要删除,怎么整。

分支没有push到远程

删除本地的分支很简单:


git branch -d branch_name

举例截图如下:

分支已经push到远程

我现在本地和远程都有一个test分支,如下图:

执行如下的命令删除本地和远程的test分支:

git push origin --delete test
git checkout master
git branch -d test
#git branch -D test 如果有未提交的文件,用它

执行完效果如下:

可以看到都删掉了。

总结

出错不可怕,可怕的是你不知道为什么出错以及如何修复错误。所谓亡羊补牢,为时未晚。

欢迎关注课程《中小型企业通用自动化运维架构 》

查看原文

赞 9 收藏 78 评论 4

DahuX 赞了文章 · 2017-07-11

HTML5拖放API Drag and Drop

此文研究Web API中的拖放接口,提供各个属性和方法的说明,解决拖放过程中的拖拽数据对象存储和获取问题。

拖放API作用到两个目标对象,分别是拖拽目标对象和放置目标对象。

拖拽目标

一个设置draggable属性的值为trueDOM元素或者一个选中状态的文本区块可以成为拖拽目标。

<div draggable="true"></div>

OR
yy 20170629201338

放置目标

一个绑定了下图放置目标对应的5个事件的DOM元素可以成为放置目标。

事件

拖放API有8个事件,其中有3个事件绑定在拖拽目标上,有5个事件绑定在放置目标上。

绑定在拖拽目标

EvnetDescription
dragstart当用户开始拖拽一个元素或者一个文本选取区块的时触发。
drag当用户正在拖拽一个元素或者一个文本选取区块的时触发。
dragend当用户结束拖拽一个元素或者一个文本选取区块的时触发。(如放开鼠标按键或按下键盘的 escap 键)

绑定在放置目标

EventDescription
dragenter当一个元素或文字选取区块被拖曳移动进入一个有效的放置目标时触发。
dragover当一个元素或文字选取区块被拖曳移动经过一个有效的放置目标时触发。
dragleave当一个元素或文字选取区块被拖曳移动离开一个有效的放置目标时触发。
dragexist当一个元素不再是被选取中的拖曳元素时触发。(Firefox能触发,触发顺序:dragexist->dragleave->drop;Chrome无法触发)
drop当一个元素或文字选取区块被放置至一个有效的放置目标时触发。

通过下图能更直观观察每个事件触发的时机

dragdrop-events

戳我看源码

注意:在dragover事件中使用event.preventDefault();阻止默认事件,才能触发drop事件

DataTransfer对象

在进行拖放操作时,会触发上面所述的8个事件,每个event事件对象中都会有DataTransfer对象用来保存被拖动的数据。它可以保存一项或多项数据、一种或者多种数据类型。

effectAllowed

用来指定拖动时被允许的效果。

dragstart事件中设置

属性

dropEffect

设置实际的放置效果,它应该始终设置成effectAllowed的可能值之一 。

dragenter事件和dragover事件中设置

effectAllowed和dropEffect属性的栗子:戳我看源码

files

包含一个在数据传输上所有可用的本地文件列表。如果拖动操作不涉及拖动文件,此属性是一个空列表。

filesZoneEl.addEventListener("drop", (event) => {
    event.preventDefault();
    let files = event.dataTransfer.files;
    for (let i = 0, len = files.length; i < len; i++) {
        let liEl = document.createElement("li");
        liEl.innerHTML = files[i].name;
        filesListEl.appendChild(liEl);
    }
});

drag-file

戳我看源码

types

保存一个被存储数据的类型列表作为第一项,顺序与被添加数据的顺序一致。如果没有添加数据将返回一个空列表。

items

存储DataTransferItem数据对象的列表。

方法

addElement()

设置拖动源。

event.dataTransfer.addElement(element);

setData()

为一个给定的类型设置数据并存储在items属性中。

getData()

items属性中获取给定类型的数据,无数据时返回空字符串。

event.dataTransfer.getData(type);

clearData()

items属性中删除与给定类型关联的数据,若类型为空则删除所有数据。

event.dataTransfer.clearData(type);

setDragImage()

自定义一个期望的拖动时的图片,默认为被拖动的节点。

event.dataTransfer.setDragImage(imgElement, offsetX, offsetY);
ParamDescription
imgElement要用作拖动反馈图像元素。
offsetX图像内的水平偏移量。
offsetY图像内的垂直偏移量。

设置拖动时的图片时,要把图片预加载,否则图片会在拖动开始dragstart事件触发时才会加载图片,会导致拖动图出不来或闪一下的后果。可把图片放到<img>标签并设置display:none;,原理详看我之前的文章Web图片资源的加载与渲染时机

drag-imgage

DataTransferItemList

dataTramsfer对象的items属性,包含了一系列DataTransferItem拖拽数据对象。

属性

length

数组长度。

方法

add()

增加一个拖拽数据对象到items属性中,并返回增加的拖拽数据对象。

event.dataTransfer.items.add(file);

remove()

items属性中移除指定位置的一个拖拽数据对象。

event.dataTransfer.items.remove(index);

clear()

清空items属性中的所拖拽数据对象。

event.dataTransfer.items.clear();

DataTransferItem

DataTransferItemList列表中的拖拽数据对象。

属性

kind

拖拽数据对象类型。

ValueDescription
file文件类型。
string文本字符串类型。

type

MIME类型的Unicode字符串,例如text/plaintext/htmlimage/png

方法

getAsFile()

若拖拽数据对象是文件类型,则返回一个文件对象。

let itemList = event.dataTransfer.items;
for (let i = 0, len = itemList.length; i < len; i++) {
    if (itemList[i].kind == "file") {
        console.log(itemList[i].getAsFile());
    }
}

getAsString()

若拖拽数据对象是文本字符串类型,通过回调函数获取拖拽数据中的字符串数据。

let itemList = event.dataTransfer.items;
for (let i = 0, len = itemList.length; i < len; i++) {
    if (itemList[i].kind == "string") {
        itemList[i].getAsString((data) => {
            console.log(data);
        });
    }
}

拖放对象的数据存储

在进行拖放操作时,有可能需要把拖拽目标的数据传送给放置目标,此时一般操作是在dragstart事件触发时把需要的数据存储到一个变量,然后再drop事件触发时获取这个变量。但当dragstart事件和drop事件在不同的文件定义,又不想玷污全局变量的情况下,我们需要更好的办法来存储拖放数据。

DataTransfer对象中的items属性就是用来存储拖放数据的,数据类型分为文本类型和文件类型。

存储文本字符串类型数据:

event.dataTransfer.setData(type, data);

OR

event.dataTransfer.items.add(data, type);

一种文本字符串类型只能存储一个数据,当重复文本字符串类型存储数据时,后者会覆盖前者。

存储文件类型数据:

event.dataTransfer.items.add(file);

获取所有文本字符串类型的拖拽数据对象

event.dataTransfer.types

获取所有文件类型的拖拽数据对象

let files = event.dataTransfer.files;
for (let i = 0, len = files.length; i < len; i++) {
    console.log(files[i]);
}

OR

let itemList = event.dataTransfer.items;
for (let i = 0, len = itemList.length; i < len; i++) {
    if (itemList[i].kind == "file") {
        console.log(itemList[i].getAsFile());
    }
}

获取所有文本字符串类型的拖拽数据对象

let itemList = event.dataTransfer.items;
for (let i = 0, len = itemList.length; i < len; i++) {
    if (itemList[i].kind == "string") {
        itemList[i].getAsString((data) => {
            console.log(data);
        });
    }
}

获取指定文本字符串类型的拖拽数据对象

event.dataTransfer.getData(type);

删除指定文本字符串类型的拖拽数据对象

event.dataTransfer.clearData(type);

删除指定位置的拖拽数据对象

event.dataTransfer.items.remove(index);

清空所有拖拽数据对象

event.dataTransfer.clearData();

OR

event.dataTransfer.items.clear();

栗子

上面的几个栗子都使用了以上方法存储和获取拖拽数据对象,感兴趣的可以看看源码。

欢迎关注:Leechikit
原文链接:segmentfault.com

到此本文结束,欢迎提问和指正。
写原创文章不易,若本文对你有帮助,请点赞、推荐和关注作者支持。

查看原文

赞 47 收藏 243 评论 6

DahuX 赞了文章 · 2017-07-04

在Vue/webpack引入第三方插件jQuery/swiper:简单易行

写在前面

日前,在学习使用Vue2.0开发新的项目。然而目前用Vue实现的UI框架里面,尚未出现具有像bootstrap一样统治力的框架。一番纠结后,老夫抄起家伙就是一梭...

那么问题来了,在Vue中如何引入jQueryswiper呢?

经历半天搜索、比对、尝试之后,得出了下面的结论,单用 webpack 时设置同理。

引入jQuery

这个问度娘就有很多方案,我这里选取的是将jQuery暴露到全局的方式,这样就不用每个用到的地方都要import一次

安装 jQuery

npm i -S jQuery //等同于 npm install --save jQuery

设置 webpack.config.js

var webpack = require('webpack')
const ProvidePlugin = new webpack.ProvidePlugin({//引入外部类库
  $: 'jquery',
  jQuery: 'jquery',
});
module.exports = {
...
plugins: [
    ProvidePlugin,
  ],
...
}

至此,可全局使用熟悉的$符号了。

更多办法

  • 使用 exports-loader(按照官方例子实测,配置简单成谜,然而无效,求指点)
  • 设置 externals详情参考推荐答案
  • 普通 import(也就是接下来要说的办法)

引入swiper插件

本来设置externals后再在index.html中引用的办法也是挺好的,但在我的项目中只有一个页面用到,而且externals方式不知如何设置css(还望高人指点),故选择普通import的方式。

vue-awesome-swiper的使用可以参考 这篇文章

此法无需在index.html引用其JSCSS,但每个用到的页面都需要import一次,jQuery也可用此法引入。

简单粗暴import

scriptimportjs文件
import Swiper from '../assets/lib/swiper-3.4.2.min.js'
style@importcss文件
@import '../assets/lib/swiper-3.4.2.min.css';

至此,可以像往常一样使用又爱又恨的swiper了。

最后

这里只举了jqswiper的例子,同理其他插件也是可用同样的方法引入。虽以上皆经过实战检验,但若有错误欢迎指正。如果对你有帮助,那就点个赞呗。逃。
查看原文

赞 7 收藏 23 评论 15

DahuX 赞了头条 · 2017-06-23

赞 8 收藏 24 评论 0

认证与成就

  • 获得 0 次点赞
  • 获得 0 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 0 枚铜徽章

擅长技能
编辑

(゚∀゚ )
暂时没有

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2015-10-23
个人主页被 218 人浏览