软件测试–mocha入门

thbcm阅读(173)

什么是TDD:

TDD:Test driven devlement,测试驱动开发,是敏捷开发中的一项核心实践和技术,也是一种设计方法论。TDD的原理是在开发功能代码之前,先编写单元测试用例代码,测试代码确定需要编写什么产品代码。

什么是mocha:

mocha是JavaScript的一种单元测试框架,既可以在浏览器环境下运行,也可以在Node.js环境下运行。

安装mocha:

1.创建一个工程。

2.运行:

#初始化
npm init
#安装mocha
npm i mocha chai -D

此时目录结构为:

编写业务代码:

编写math.js用于模拟业务代码

function add(x,y){
    return x+y;
}

function multiply (x,y){
    return x*y;
}

module.exports={
    add,multiply 
}

编写测试代码:

//导入刚刚写的math.js
var math=require("../math");
//导入断言
var assert= require("assert");
// 描述测试文件
describe('测试math.js',function(){
    // 描述测试的方法
    describe('测试方法add',function(){
        // mocha提供了it方法,称为测试用例,表示一个单独的测试
        // 我们可以写某个方法的多个测试用例来测试不同情况下的状况
        // 测试10+1;
        it('10+1',function(){
            // 断言10+1=11
            assert.equal(math.add(10,1),11);
        });
        // 测试不通过
        // 测试10+2;断言10+2=9
        it("10+2",function(){
            assert.equal(math.add(10,2),9)
        })
    });
    describe("测试方法multiply",function(){
        // 测试5*2
        it('5-2',function(){
            // 断言5*2=10
            assert.equal(math.multiply(5,2),10);
        })
    });
})

配置package.json:

直接使用mocha测试显示在终端

"scripts": {
    "test": "mocha"
  }

运行测试:

npm test

结果:

推荐好课:

Vue.js三天学习实战教程

JavaScript实战:动态网站开发

Javascript移动端App实战开发

Node.js微课

软件测试教程

Java main方法中的String[] args详解

thbcm阅读(186)

在每一个学习Java的同学,都应该写过下面的这一段代码。

public class Hello{
	public static void main(String[] args) {
		System.out.println("Hello,World!");
	}
}

在Java语言中,规定了入口函数是一个main()方法,该方法有一个String[]类型的参数,但是在很多时候,很多人都使用不上这个参数,也不关心为什么要写这个参数。

那么这个字符串数组类型的参数究竟是什么东西呢?

其实很简单,main()方法中的字符串数组类型的参数就是java命令的参数,使用java命令的方式运行main()方法,会将java命令的参数入参到Java main()方法的字符串数组参数中。

我们可以通过以下方式来进行验证:

  • 1、先编写一个Hello.java文件,文件内容如下:
public class Hello{
	public static void main(String[] args) {
		System.out.println("==============args start============");
		for(int i = 0; i < args.length; i++) {
			System.out.println(args[i]);
		}
		System.out.println("==============args end============");
	}
}
  • 2、在Hello.java文件的路径下打开cmd命令提示符,运行javac Hello.java命令编译该文件,这将会在对应的文件路径下,得到一个Hello.class字节码文件。
  • 3、使用java Hello命令运行Hello.class文件,我们将会得到如下的运行结果:
  • 4、我们这次在java命令后面添加一些参数,这些参数我们可以自己定义。例如:java Hello a b c d ,我们将会得到如下的运行结果:

正是因为Java main()方法的这个扩展性,使得每一个开发者,可以通过自己定义一些Java命令的参数,实现一些不同的功能。

其中SpringBoot的启动类,其实也使用了这个特性,SpringApplication.run()方法有一个重载方法,其中第一个入参的是注解了@SpringBootApplication注解的类的字节码对象,而第二个参数,即为main()方法的字符串数组参数。

SpringBoot可以通过这个字符串数组参数,通过java命令参数的方式,在不同的环境下实现不同的应用配置。

@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

推荐好课:

Java:23天零基础完全入门

Java开发实例:坦克大战游戏

Java基本数据类型,看这一篇就够了!

thbcm阅读(174)

相信学过Java的小伙伴们都知道,Java是强类型语言,所以Java对于数据类型的规范会相对严格。

它提供了八种基本类型(这里不讲解Void)。其中六种数字类型(四个整数型(默认是int 型),两个浮点型(默认是double 型)),一种字符类型,还有一种布尔型。

基础

我们先来一点干货!!

基本数据类型 大小 值域 默认值 包装器类型
boolean true,false false Boolean
char 16 bit [0,216-1] ‘\u0000’ Character
byte 8 bit [-128,127] 0 Byte
short 16 bit [-215,215-1] 0 Short
int 32 bit [-231,231-1] 0 Integer
long 64 bit [-263,263-1] 0L Long
float 32 bit [-3.4E38,3.4E38] 0.0F Float
double 64 bit [-1.8E308,1.8E308] 0.0D Double

如果掌握了这些要点,那说明基础是不错的,有兴趣的话可以随小编再深入了解一下!!

深入

数据类型在计算机语言里面,是对程序所处理数据的抽象,它存在的意义是为了方便虚拟机为不同的数据分配更合适的空间。所以,对数据类型的理解自然与虚拟机分不开。

在 Java 虚拟机规范中,boolean 类型则被映射成 int 类型。具体来说,“true”被映射为整数 1,而“false”被映射为整数 0。这个编码规则约束了 Java 字节码的具体实现。

Java 虚拟机规范同时也要求 Java 编译器遵守这个编码规则,并且用整数相关的字节码来实现逻辑运算,以及基于 boolean 类型的条件跳转。这样一来,在编译而成的 class 文件中,除了字段和传入参数外,基本看不出 boolean 类型的痕迹了。

Java 的基本类型都有对应的值域和默认值。

可以看到,byte、short、int、long、float 以及 double 的值域依次扩大,而且前面的值域被后面的值域所包含。因此,从前面的基本类型转换至后面的基本类型,无需强制转换。另外一点值得注意的是,尽管他们的默认值看起来不一样,但在内存中都是 0。

在这些基本类型中,boolean 和 char 是唯二的无符号类型。boolean 类型的取值范围是 0 或者 1,char 类型的取值范围则是 [0, 65535]。通常我们可以认定 char 类型的值为非负数,这种特性十分有用,比如说作为数组索引等。

数据存储

Java 虚拟机每调用一个 Java 方法,便会创建一个栈帧。这种栈帧有两个主要的组成部分,分别是局部变量区,以及字节码的操作数栈。

在 Java 虚拟机规范中,局部变量区等价于一个数组,并且可以用正整数作为索引。除了 long、double 值需要用两个数组单元来存储之外,其他基本类型以及引用类型的值均占用一个数组单元。也就是说,boolean、byte、char、short 这四种类型,在栈上占用的空间和 int 是一样的,和引用类型也是一样的。

因此,当我们将一个 int 类型的值,存储到这些类型的字段或数组时,相当于做了一次隐式的掩码操作。举例来说,当我们把 0xFFFFFFFF(-1)存储到一个声明为 char 类型的字段里时,由于该字段仅占两字节,所以高两位的字节便会被截取掉,最终存入“\uFFFF”。

数据加载

Java 虚拟机的算数运算几乎全部依赖于操作数栈。也就是说,我们需要将堆中的 boolean、byte、char 以及 short 加载到操作数栈上,而后将栈上的值当成 int 类型来运算。

对于 boolean、char 这两个无符号类型来说,加载伴随着零扩展。举例来说,char 的大小为两个字节,在加载时 char 的值会被复制到 int 类型的低二字节,而高二字节则会用 0 来填充。

对于 byte、short 这两个类型来说,加载伴随着符号扩展。举个例子,short 的大小为两个字节。在加载时 short 的值同样会被复制到 int 类型的低二字节。如果该 short 值为非负数,即最高位为 0,那么该 int 类型的值的高二字节会用 0 来填充,否则用 1 来填充。

小结

基础知识要掌握好,底层实现也需要有一定的认识。了解虚拟机,有助于理解Java语言的一些性质,也有助于使用Java语言。

推荐阅读:

Java:23天零基础完全入门

深入解析Java面向对象

Java8编程开发入门

python 五种常见的测试框架

thbcm阅读(192)

一. unittest

unittest 和 JUnit类似,可以说是python的标准单元测试框架,所以有时也被人称为 PyUnit。它使用起来和xUnit 家族其他成员类似。 用的人也比较多。兼容 python2 以及python3 。

个人比较喜欢用这个,主要之前用过JUnit,用这个上手就很快。而且属于python自动集成,不用额外的安装包,感觉是该有的都有了,用着方便。

官网示例:

按 Ctrl+C 复制代码

import unittest

class TestStringMethods(unittest.TestCase):

def test_upper(self): self.assertEqual(‘foo’.upper(), ‘FOO’)

def test_isupper(self): self.assertTrue(‘FOO’.isupper()) self.assertFalse(‘Foo’.isupper())

def test_split(self): s = ‘hello world’ self.assertEqual(s.split(), [‘hello’, ‘world’]) # check that s.split fails when the separator is not a string with self.assertRaises(TypeError): s.split(2)

if name == ‘main’: unittest.main()

二. unittest2

unittest2 可以说是一个针对 unittest 测试框架新特性的补丁。它很大程度上和 unittest 都类似。然后还添加了一些 unittest 没有的方法。

三. pytest

看了一下,pytest 文档还是蛮详细的。比较关注的一点是,pytest 直接可以通过 @pytest.mark.parametrize 进行参数化,而 unittest 则需要借助 DDT。

官网示例:

# content of test_sample.py
def inc(x):
  return x + 1

def test_answer():
  assert inc(3) == 5

执行如下:

$ pytest
======= test session starts ========
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y
rootdir: $REGENDOC_TMPDIR, inifile:
collected 1 item

test_sample.py F

======= FAILURES ========
_______ test_answer ________

  def test_answer():
>       assert inc(3) == 5
E       assert 4 == 5
E       + where 4 = inc(3)

test_sample.py:5: AssertionError
======= 1 failed in 0.12 seconds ========

四. nose

nose 扩展了 unittest,从而使得测试更容易。

一般可以用 unittest 方式写用例,写完之后用 nose 来执行。nose 的测试收集方式还是很方便的。

还有一个特定就是,nose 可以采用 @with_setup() 来定义方法的 setup 和 teardown。

官方示例:

def setup_func():
  "set up test fixtures"

def teardown_func():
  "tear down test fixtures"

@with_setup(setup_func, teardown_func)
def test():
  "test ..."

五. doctest

doctest 模块会搜索那些看起来像交互式会话的 Python 代码片段,然后尝试执行并验证结果。

doctest 中,如果要写测试用例,只需要在写在以 ”’ ”’包围的文档注释即可,也就是可以被 doc 这个属性引用到的地方。这点比较特别,跟其他单元测试框架都不一样。但是我觉得这样的话就注定了 doctest 不适合大型测试,因为做不到代码和测试的分离。

import doctest

"""
This is the "example" module.

The example module supplies one function, factorial(). For example,

>>> factorial(5)
120
"""

def factorial(n):
  """Return the factorial of n, an exact integer >= 0.

  >>> [factorial(n) for n in range(6)]
  [1, 1, 2, 6, 24, 120]
  >>> factorial(30)
  265252859812191058636308480000000
  >>> factorial(-1)
  Traceback (most recent call last):
      ...
  ValueError: n must be >= 0

  Factorials of floats are OK, but the float must be an exact integer:
  >>> factorial(30.1)
  Traceback (most recent call last):
      ...
  ValueError: n must be exact integer
  >>> factorial(30.0)
  265252859812191058636308480000000

  It must also not be ridiculously large:
  >>> factorial(1e100)
  Traceback (most recent call last):
      ...
  OverflowError: n too large
  """

  import math
  if not n >= 0:
      raise ValueError("n must be >= 0")
  if math.floor(n) != n:
      raise ValueError("n must be exact integer")
  if n+1 == n: # catch a value like 1e300
      raise OverflowError("n too large")
  result = 1
  factor = 2
  while factor <= n:
      result *= factor
      factor += 1
  return result


if __name__ == "__main__":
  doctest.testmod(verbose=True)

verbose 参数用于控制是否输出详细信息,默认为 False ,如果不写,那么运行时不会输出任何东西,除非测试 fail。

输出如下:

Trying:
  [factorial(n) for n in range(6)]
Expecting:
  [1, 1, 2, 6, 24, 120]
ok
Trying:
  factorial(30)
Expecting:
  265252859812191058636308480000000
ok
Trying:
  factorial(-1)
Expecting:
  Traceback (most recent call last):
      ...
  ValueError: n must be >= 0
ok
Trying:
  factorial(30.1)
Expecting:
  Traceback (most recent call last):
      ...
  ValueError: n must be exact integer
ok
Trying:
  factorial(30.0)
Expecting:
  265252859812191058636308480000000
ok
Trying:
  factorial(1e100)
Expecting:
  Traceback (most recent call last):
      ...
  OverflowError: n too large
ok
1 items had no tests:
  __main__
1 items passed all tests:
  6 tests in __main__.factorial
6 tests in 2 items.
6 passed and 0 failed.
Test passed.

推荐好课:python3入门python3进阶

JQuery的增加元素,删除元素

thbcm阅读(171)

JQuery的增加元素,删除元素

1. jQuery创建元素方法

let div = $('<div>elm</div>');

$(‘<div>elm</div>’)可以创建一个div元素,并内容为elm

2.添加元素

2.1.内部添加 append(),prepend()方法

<ul>
   <li>原有的</li>
</ul>
<script>
   $(function() {
       let li = $('<li>后加的</li>');
       $('ul').append(li);
  });
</script>

append()方法会把元素添加到匹配元素最后面,类似原生JS里的appendChild()

<ul>
  <li>原有的</li>
</ul>
<script>
  $(function() {
      let li = $('<li>后加的</li>');
      $('ul').prepend(li);
  });
</script>

prepend()方法会把元素添加到匹配元素最前面,类似原生JS里的insertBefore()

内部添加元素后,生成的是父子关系

2.2.外部添加 before(),after()方法

原来的    $(function() {        let div = $(‘ 添加的 ‘);        $(‘div’).before(div);   })

before()方法会把元素添加在匹配元素前面

<div>原来的</div>
<script>
   $(function() {
       let div = $('<div>添加的</div>');
       $('div').after(div);
  })
</script>

after()方法会把元素添加在匹配元素后面

外部添加元素,生成的是兄弟关系

2.删除元素

1.remove()

<ul>
   <li></li>
</ul>
<script>
   $(function() {
       $('ul').remove();
  })
</script>

remove()会删除ul元素,包括子节点

2.empty()

<ul>
   <li></li>
</ul>
<script>
   $(function() {
       $('ul').empty();
  })
</script>

empty()清空ul节点内的所有子节点,但会保留ul自身节点

3.html(“”)

html(“”)方法作用于empty()基本一致

推荐好课:jquery微课jquery入门

DOM操作_获取元素

thbcm阅读(177)

概述

DOM (Document objectModal) :文档对象模型。

DOM:是浏览器提供的(浏览器特有),专门用来操作网页内容的一些JS对象。

目的:让我们可以使用 Js/TS 代码来操作页面(HTML) 内容,让页面“动”起来,从而实现 Web 开发。

HTML:超文本标记语言,用来创建网页结构。

两者的关系:浏览器根据 HTML 内容创建相应的 DOM 对象,也就是:每个 HTML 标签都有对应的 DOM 对象

获取元素

常用方法有两个:

querySelector (selector)作用:获取某一个DOM元素。

queryseletor (selectocu)作用:同时获取多个D0M元素。

获取一个DOM元素:

document. querySelector (selector) document 对象:文档对象(整个页面),是操作页面内容的入口对象。 selector 参数:是一个 css 选择器(标签、类、id 选择器等)。 作用:查询(获取)与选择器参数匹配的 DOM 元素,但是,只能获取到第一个 推荐使用id选择器,例如

获取html中id为title的标签内容并在控制台输出:
let title = document.querySelector('#title')
console.log(title)

结果如下

调用 querySelector ()通过id选择器获取 DOM 元素时,拿到的元素类型都是 Element. 因为无法根据id来确定元素的类型,所以,该方法就返回了一个宽泛的类型:元素(Element) 类型。 不管是 h1 还是 img 都是元素。 导致新问题:无法访问 img 元素的 src 属性了。 因为: Element 类型只包含所有元素共有的属性和方法(比如: id 属性)。

解决方式:使用类型断言,来手动指定更加具体的类型(比如,此处应该比 Element 类型更加具体)。 比如: 解释:我们确定 id=” image”的元素是图片元素,所以,我们将类型指定为 HTML ImageElement。

let img1 = document.querySelector('#img1') as HTMLImageElement

img1.src = './img/4.jpg'
如何知道元素的属性?

技巧:通过 console.dir()打印 DOM 元素,在属性的最后面,即可看到该元素的类型。

let img1 = document.querySelector('#img1') as HTMLImageElement

img1.src = './img/4.jpg'

console.dir(img1)

获取多个 DOM元素:

document . querySelectorAll (selector) 作用:获取所有与选择器参数匹配的 DOM 元素,返回值是一个列表。 推荐:使用 class 选择器。 示例: let、list = document . querySelectorAll(’.a’) 解释:获取页面中所有 class 属性包含 a 的元素。

html中的内容如下
<p id='title'>欢迎来到海南大学</p>
   <p class = ' a'>2020年时多灾多难的一年</p>
   <p class="b a">2021年将牛气冲天</p>
   <img id = 'img1'src="./img/1.jpg" alt="">
   <script src = './index.js'></script>
ts 中的内容如下
let list = document.querySelectorAll('.a')

console.log(list)
运行结果如下

操作文本内容

读取: dom. innerText 设置: dom. innerText = ’ 等你下课’ 注意:需要通过类型断言来指定 DOM 元素的具体类型,才可以使用innerText 属性。 例如

let title = document.querySelector('#title') as HTMLParagraphElement
console.log(title.innerHTML)

追加内容如下操作

let title = document.querySelector('#title') as HTMLParagraphElement
title.innerHTML = title.innerHTML + ' 阳光沙滩美女'
console.log(title.innerHTML)
给所有p标签的内容加上索引
let list = document.querySelectorAll('.a') 

list.forEach(function (item,index) {
   let p = item as HTMLParagraphElement
   p.innerHTML = '['+index+']'+p.innerHTML
})

输出结果如下:

如何进行数据埋点?

thbcm阅读(175)

埋点一种良好的私有化部署数据采集方式, 当然,本文主要是针对代码埋点的方式进行讲解。

1.明确埋点目的

通俗点讲,就是说到底我们需要去看哪些数据,比如是要看某篇文章分享的是不是够多,或者点了付款单付款成功人数的比例有多少,一般可以大致分为三类:用户基本数据、功能使用数据、综合数据。

2. 梳理业务流程

梳理业务流程,其实并不是必须的,只是针对一些比较复杂的用户操作流程而言,是需要特别注意,因为有一些是需要通过多个步骤计算得到一个百分比,比如用户的下单流程,大致需要经过注册->登录->浏览列表->访问详情->立即购买->确认订单->付款,那这就涉及到在每个环节上用户的流失情况,从而可以推断出最终的付款转化情况。

而有一些埋点目的相对比较单纯简单,就是想对比下多个入口的受欢迎程度,那么就直接在各个入口埋点即可,因为不涉及到什么流程,只是需要统计它们的点击次数即可。

3.定义埋点事件

作为产品来说,我们需要定义事件的id、事件名称,事件id是需要开发工程师写到代码里面的英文字段事件名称则是为了自己能明白埋的到底是啥的,还需要跟英文字段对应的一个名称,而对于有的平台比如友盟还需要去定义事件类型,它可以定义成多参数类型事件或者计算事件

那除了上面这些在埋点的第三方平台上必须要去提交的参数外,为了让产品自己能够在过了很久以后,或者其他同事能够知道之前某个埋点到底是代表什么意思,一般我们还会去整理某个埋点对应的是哪个功能模块,以及简单的描述某个埋点的说明,可以用Excel表格进行整理,大概可以如下:

4.进行数据采集

在产出了上面的埋点需求表格以后,就把这个表格给开发工程师就可以了,当然在这之前,还需要把对应的事件录入到数据统计的平台上,以确保我们能够正常的看到数据,比如友盟平台就是在事件管理里去进行事件的添加,然后去填写事件 id、事件名称并选择事件的类型,当然也可以用批量添加的方式,具体模板不同平台略有差异,需要添加的时候去各个平台上查看即可。

另外一个目的就是想要监控用户开通会员的入口来源,所以我们在有开通会员的入口位置加上了相应的埋点,命名为clickOpen,同时给这个事件加上了参数也就是上图的属性fromPage,并指定了来源一个是Banner,一个是首页弹出的Dialog

5. 添加埋点

所以整理完上面的埋点需求以后,我们就把对应的事件添加到了友盟的后台(可以选择批量添加多个或者手动单个去添加,下图是单个添加的截图),同时把上面的需求交给了开发工程师去进行埋点。

原生js中用DOM操作table以及表格搜索功能

thbcm阅读(162)

DOM中table的便捷操作

tBobies(数组) tHead tFoot rows(行) cells(单元格)

<body>
  <table border="1" id="table1" width="500">
      <thead>
           <tr>
              <td>ID</td>
               <td>姓名</td>
               <td>年龄</td>
           </tr>
       </thead>
       <tbody>
           <tr>
               <td>1</td>
               <td>张三</td>
              <td>23</td>
           </tr>
       </tbody>
  </table>
   <script>
       window.onload = function () {
           var oTable = document.getElementById('table1')
   alert(oTable.getElementsByTagName('tbody')[0].getElementsByTagName('tr')[0].getElementsByTagName('td')[1].innerHTML)
           alert(oTable.tBodies[0].rows[0].cells[1].innerHTML)
      }
   </script>
</body>

隔行变色、高亮

<body>
   <table border="1" id="table1" width="500">
       <thead>
           <tr>
              <td>ID</td>
              <td>姓名</td>
               <td>年龄</td>
          </tr>
      </thead>
      <tbody>
           <tr>
              <td>1</td>
              <td>张三</td>
               <td>23</td>
           </tr>
           <tr>
               <td>2</td>
               <td>里斯</td>
               <td>24</td>
           </tr>
           <tr>
              <td>3</td>
               <td>王武</td>
               <td>25</td>
           </tr>
       </tbody>
   </table>
   <script>
       window.onload = function () {
           var oTable = document.getElementById('table1');
           var oldColor = '' //原来的背景颜色
           alert(oTable.tBodies[0].rows.length)
           for(var i = 0; i < oTable.tBodies[0].rows.length; i++){
               oTable.tBodies[0].rows[i].onmouseover = function(){
                   oldColor = this.style.background; //将原来的背景颜色保存起来
                   this.style.background = 'yellow'
              }
               oTable.tBodies[0].rows[i].onmouseout = function(){
                   this.style.background = oldColor
              }
               if(i % 2){ // i%2为0时,条件为假
                   oTable.tBodies[0].rows[i].style.background = "#999"
              }else{
                   oTable.tBodies[0].rows[i].style.background = ""
              }
          }
      }
   </script>
</body>

添加行、删除行

<body>
   <input type="text" id="name">
   <input type="text" id="age">
   <input type="button" id="btn" value="添加">
   <table border="1" id="table1" width="500">
       <thead>
           <tr>
               <td>ID</td>
               <td>姓名</td>
               <td>年龄</td>
               <td>操作</td>
           </tr>
       </thead>
       <tbody></tbody>
   </table>
   <script>
       window.onload = function () {
           var oTable = document.getElementById('table1'); //获取table
           var oName = document.getElementById('name') //获取姓名文本框
           var oAge = document.getElementById('age') //获取年龄文本框
           var oBtn = document.getElementById('btn') //获取添加按钮
           var id = oTable.tBodies[0].rows.length + 1; //将 id 的值作为全局变量保存,避免 id 重复
           oBtn.onclick = function () {  
               var oTr = document.createElement('tr') //创建 tr 元素
              oTr.innerHTML = '<td>' + (id++) + '</td><td>' + oName.value + //给 tr 赋值
                  '</td><td>' +
                   oAge.value + '</td><td><a href="javascript:;">删除</a></td>'
               oTr.getElementsByTagName('a')[0].onclick = function () {  // 给删除按钮设置点击时间
                   oTable.tBodies[0].removeChild(this.parentNode.parentNode)
              }
               oTable.tBodies[0].appendChild(oTr)
          }
      }
   </script>
</body>

表格搜索、忽略大小写、模糊查询

DOM中table的便捷操作

tBobies(数组) tHead tFoot rows(行) cells(单元格)

<body>
  <table border="1" id="table1" width="500">
      <thead>
           <tr>
              <td>ID</td>
               <td>姓名</td>
               <td>年龄</td>
           </tr>
       </thead>
       <tbody>
           <tr>
               <td>1</td>
               <td>张三</td>
              <td>23</td>
           </tr>
       </tbody>
  </table>
   <script>
       window.onload = function () {
           var oTable = document.getElementById('table1')
   alert(oTable.getElementsByTagName('tbody')[0].getElementsByTagName('tr')[0].getElementsByTagName('td')[1].innerHTML)
           alert(oTable.tBodies[0].rows[0].cells[1].innerHTML)
      }
   </script>
</body>

隔行变色、高亮

<body>
   <table border="1" id="table1" width="500">
       <thead>
           <tr>
              <td>ID</td>
              <td>姓名</td>
               <td>年龄</td>
          </tr>
      </thead>
      <tbody>
           <tr>
              <td>1</td>
              <td>张三</td>
               <td>23</td>
           </tr>
           <tr>
               <td>2</td>
               <td>里斯</td>
               <td>24</td>
           </tr>
           <tr>
              <td>3</td>
               <td>王武</td>
               <td>25</td>
           </tr>
       </tbody>
   </table>
   <script>
       window.onload = function () {
           var oTable = document.getElementById('table1');
           var oldColor = '' //原来的背景颜色
           alert(oTable.tBodies[0].rows.length)
           for(var i = 0; i < oTable.tBodies[0].rows.length; i++){
               oTable.tBodies[0].rows[i].onmouseover = function(){
                   oldColor = this.style.background; //将原来的背景颜色保存起来
                   this.style.background = 'yellow'
              }
               oTable.tBodies[0].rows[i].onmouseout = function(){
                   this.style.background = oldColor
              }
               if(i % 2){ // i%2为0时,条件为假
                   oTable.tBodies[0].rows[i].style.background = "#999"
              }else{
                   oTable.tBodies[0].rows[i].style.background = ""
              }
          }
      }
   </script>
</body>

添加行、删除行

<body>
   <input type="text" id="name">
   <input type="text" id="age">
   <input type="button" id="btn" value="添加">
   <table border="1" id="table1" width="500">
       <thead>
           <tr>
               <td>ID</td>
               <td>姓名</td>
               <td>年龄</td>
               <td>操作</td>
           </tr>
       </thead>
       <tbody></tbody>
   </table>
   <script>
       window.onload = function () {
           var oTable = document.getElementById('table1'); //获取table
           var oName = document.getElementById('name') //获取姓名文本框
           var oAge = document.getElementById('age') //获取年龄文本框
           var oBtn = document.getElementById('btn') //获取添加按钮
           var id = oTable.tBodies[0].rows.length + 1; //将 id 的值作为全局变量保存,避免 id 重复
           oBtn.onclick = function () {  
               var oTr = document.createElement('tr') //创建 tr 元素
              oTr.innerHTML = '<td>' + (id++) + '</td><td>' + oName.value + //给 tr 赋值
                  '</td><td>' +
                   oAge.value + '</td><td><a href="javascript:;">删除</a></td>'
               oTr.getElementsByTagName('a')[0].onclick = function () {  // 给删除按钮设置点击时间
                   oTable.tBodies[0].removeChild(this.parentNode.parentNode)
              }
               oTable.tBodies[0].appendChild(oTr)
          }
      }
   </script>
</body>

表格搜索、忽略大小写、模糊查询

<body>
  姓名:<input type="text" id="name"><input type="button" value="搜索" id="btn">
   <table border="1" id="table1" width="500">
       <thead>
           <tr>
               <td>ID</td>
               <td>姓名</td>
               <td>年龄</td>
           </tr>
       </thead>
       <tbody>
           <tr>
               <td>1</td>
               <td>张三</td>
               <td>23</td>
           </tr>
           <tr>
               <td>2</td>
               <td>里斯</td>
               <td>24</td>
           </tr>
       </tbody>
   </table>
   <script>
       window.onload = function () {
           var oTable = document.getElementById('table1');
           var oName = document.getElementById('name')
           var oBtn = document.getElementById('btn')
           oBtn.onclick = function()
          {
       for(var i = 0; i < oTable.tBodies[0].rows.length; i++){ //循环每一行
       var oTd = oTable.tBodies[0].rows[i].cells[1].innerHTML.toLowerCase()
                   var oInp = oName.value.toLowerCase()
//if(oTd == oInp){ //比较每一行的第二列和文本行的值是否相等//if(oInp.toLowerCase() == oTd.toLowerCase()){ //将值先转成小写,再进行比较, 或者全部转成大写 toUpperCase()if(oTd.search(oInp) != -1){ //字符串中的search(),如果包含返回字符的位置、不包含返回 -1
         oTable.tBodies[0].rows[i].style.background = 'red'
          }else{
             oTable.tBodies[0].rows[i].style.background = ''
                  }
              }
          }
      }
   </script>
</body>
<body>
  姓名:<input type="text" id="name"><input type="button" value="搜索" id="btn">
   <table border="1" id="table1" width="500">
       <thead>
           <tr>
               <td>ID</td>
               <td>姓名</td>
               <td>年龄</td>
           </tr>
       </thead>
       <tbody>
           <tr>
               <td>1</td>
               <td>张三</td>
               <td>23</td>
           </tr>
           <tr>
               <td>2</td>
               <td>里斯</td>
               <td>24</td>
           </tr>
       </tbody>
   </table>
   <script>
       window.onload = function () {
           var oTable = document.getElementById('table1');
           var oName = document.getElementById('name')
           var oBtn = document.getElementById('btn')
           oBtn.onclick = function()
          {
       for(var i = 0; i < oTable.tBodies[0].rows.length; i++){ //循环每一行
       var oTd = oTable.tBodies[0].rows[i].cells[1].innerHTML.toLowerCase()
                   var oInp = oName.value.toLowerCase()
//if(oTd == oInp){ //比较每一行的第二列和文本行的值是否相等//if(oInp.toLowerCase() == oTd.toLowerCase()){ //将值先转成小写,再进行比较, 或者全部转成大写 toUpperCase()if(oTd.search(oInp) != -1){ //字符串中的search(),如果包含返回字符的位置、不包含返回 -1
         oTable.tBodies[0].rows[i].style.background = 'red'
          }else{
             oTable.tBodies[0].rows[i].style.background = ''
                  }
              }
          }
      }
   </script>
</body>

JavaScript原生实现年份轮播选择效果

thbcm阅读(171)

前言

用 js 实现一个年份轮换选择效果。废话不多说,看图:

一、思路是什么?

  • 布局: 左右箭头使用实体字符 < 和 > 年份5个 span。使用用 flex 布局横向排列。
  • js逻辑:(注:年份数据为 number 数组)a> . 默认展示年份数据前5个。b>. firstIndex 记录要显示的5个年份的起始索引。点击右侧箭头 +1,直到 firstIndex+5 刚好等于年份数组长度,不在递增。点击左侧箭头 -1,直到 firstIndex 为 0,不在递减。初始值为 0。c>.selectedIndex 记录当前点击选中的年份索引。默认显示第一个即 2021。初始值 0。d>.firstIndex 值发生变化,获取 firstIndex,firstIndex+1,firstIndex+2…firstIndex+4 对应的年份,渲染到页面。并且这5个索引中某一个和 selectedIndex 相等,说明选中的年份,刚好在当前页面显示的年份当中。所以,与之相等的 index 对应的 span 添加选中样式,其他4个 span 移除选中样式。
  • css:左右箭头逻辑,默认全部添加可点击样式:firstIndex=0,移除左可点击样式,firstIndex+5=年份数组长度,移除右可点击样式。

二、全部代码

1. html

代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <title>Title</title>
   <link rel="stylesheet" href="index.css" type="text/css"/>
   <script type="text/javascript" src="echarts.min.js"></script>
   <script type="text/javascript" src="index.js"></script>
</head>
<body>
<div class="container">

   <div id="left" class="arrow_left" onclick="clickBefore()" style="cursor:default" unselectable="on" onselectstart="return false;">
       <span><</span>
   </div>
   <div id="wrap" class="wrap">
       <span onclick="selected(this)">1</span>
       <span onclick="selected(this)">2</span>
       <span onclick="selected(this)">3</span>
       <span onclick="selected(this)">4</span>
       <span onclick="selected(this)">5</span>
   </div>
   <div id="right" class="arrow_right arrow_active" onclick="clickNext()" style="cursor:default" unselectable="on" onselectstart="return false;">
       <span>></span>
   </div>

</div>

<div class="content" id="content">

</div>
</body>
</html>

2.js

代码如下:

window.onload = function () {
   /*首次渲染列表*/
   initList(firstIndex);
};

let yearArr = [2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021];
yearArr.reverse();

/*起始索引*/
let firstIndex = 0;
/*选中索引,默认选中第一个*/
let selectedIndex = 0;


/**
* 初始化列表
*/
function initList(firstIndex) {

   /*渲染页面span列表*/
   let spanList = document.getElementById('wrap').getElementsByTagName('span');
   for (let i = 0; i < spanList.length; i++) {
       let index = firstIndex + i;
       let span = spanList[i];
       span.innerText = yearArr[index];

       /*选中样式添加和移除*/
       if (index === selectedIndex) {
           span.classList.add('active');
      } else {
           span.classList.remove('active')
      }
  }
   /*页面内容显示值*/
   document.getElementById('content').innerText = '当前选中年份:' + yearArr[selectedIndex];
}

/**
* 下一页
*/
function clickNext(div) {
   if (firstIndex + 5 < yearArr.length) {
       firstIndex = firstIndex + 1;
       initList(firstIndex)
  }
   arrowActive();
}

/*
* 上一页
*/
function clickBefore(div) {
   if (firstIndex > 0) {
       firstIndex = firstIndex - 1;
       initList(firstIndex)
  }
   arrowActive();
}

/**
* 选中
*/
function selected(span) {
   let value = span.innerText;
   let index = yearArr.findIndex((el) => {
       return el + "" === value;
  })
   selectedIndex = index !== -1 ? index : 0;
   initList(firstIndex);
}

/**
* 左右箭头激活
* firstIndex = 0: 右激活 左不
* firstIndex = length-5:左激活 右不
* 其他:全激活
*/
function arrowActive() {
   let left = document.getElementById('left')
   let right = document.getElementById('right')
   left.classList.add('arrow_active');
   right.classList.add('arrow_active');
   if (firstIndex === 0) {
       left.classList.remove('arrow_active');
  } else if (firstIndex === yearArr.length - 5) {
       right.classList.remove('arrow_active');
  }
}

2.css

代码如下:

body{
   margin-top: 80px;
}
.container {

   display: flex;
   justify-content: center;
   align-items: center;
   margin: 10px;
}

.wrap {
   height: 40px;
   z-index: 1;
   color: black;
   display: flex;
   flex: 1;
   background: rgba(155,226,219,0.5);
   border-radius: 20px;
   margin-left: 20px;
   margin-right: 20px;
}

.wrap span {
   flex: 1;
   text-align: center;
   height: 40px;
   line-height: 40px;
   border-radius: 20px;

}

.active{
   background: #1abc9c;
   color:#fff;
}



.arrow_left {
   left: 10px;
   color: green;
   padding: 0px 14px;
   border-radius: 50%;
   font-size: 30px;
   z-index: 2;
}


.arrow_right {
   right: 10px;
   color: green;
   padding: 0px 14px;
   border-radius: 50%;
   font-size: 30px;
   z-index: 2;
}
.arrow_active{
   color: blue;
}

.content{
   margin-left: 30px;
}

推荐好课:JavaScript微课ES6微课

用VUE实现一个简单的学生信息管理系统

thbcm阅读(169)

一、主要功能

本次任务主要是使用 VUE 来实现一个简单的学生信息管理系统,主要功能为:

1.显示所有学生的信息(默认为10个) \2. 点击按钮,显示出学号尾号为单数(或双数)的学生信息 \3. 增加学生信息 \4. 要求使用VUE中 父子组件间通信

二、实现思路

1.数据管理:使用 json 数组的方式来管理储存数据
2.显示学生信息:因为组件是可复用的 Vue 实例,所以在这里引入子组件(用来显示每个学生的信息),将主页作为父组件。主页(父组件)使用 v-for 循环显示子组件。
3.按单双号筛选查找学生:循环遍历 json 数组,进行判断,把符合条件的信息放到新的 json 数组。
4.使用 v-if 把符合筛选条件的学生信息显示在主页上。

三、代码实现

1、父子组件定义

父组件 :首先要定义要调用的组件

export default {
 name: 'HelloWorld',
 components: {
   ChildCom//调用组件
},

子组件:

export default {
 name: 'Child',
 props: [
   'card_item'
],
 data () {
   return {
  }
}
}

2、组件中的通信

组件是通过 Prop 向子组件传递数据的

父组件:使用 v-for 遍历学生信息数组 通过:card_item(子组件定义的接受数据的名字) = “stu”(父组件传给子组件的数据)

    <div  v-if="flag_danshu==1"><Child-com id="1" class="list" v-for="(stu,index1) in new_list_danshu" :key="index1" :card_item="stu" ></Child-com></div>
   <div v-else-if="flag_shuangshu==1"><Child-com id="2" class="list" v-for="(stu,index2) in new_list_shuangshu" :key="index2" :card_item="stu"  ></Child-com></div>
   <div v-else-if="flag_all==1"><Child-com id="3" class="list" v-for="(stu,index3) in stu_list" :key="index3" :card_item="stu"></Child-com></div>

子组件:

      <div>姓名:{{ card_item.name }} </div>
     <div>学号:{{card_item.stuId}}</div>
     <div v-if="card_item.gender==1">性别:男</div>
     <div v-else>性别:女</div>

3、显示出学号尾号为单数(或双数)的学生信息(以单数为例)

 danshu (stu_list) {
       this.new_list_danshu=[];
      stu_list.forEach((item) => {
        if(item.stuId%2!=0)
        this.new_list_danshu.push(item);//符合条件则加进用来存储单数信息的json数组
        }
    )
     // alert(this.new_list[1]);
     this.flag_all=0; //显示全部
     this.flag_danshu=1;//显示单数
     this.flag_shuangshu=0;//显示双数
     
  },

4、增加学生信息

 add:function(){
   var name = document.getElementById("stu_name").value;
   var id = document.getElementById("stu_id").value;
   var gender = document.getElementById("stu_gender").value;
   if(name==''||id==''||gender==''){
     alert('请完善信息');
    }
     else{
       var item ={};
       item.stuId=id;
       item.name=name;
       item.gender=gender;
       this.stu_list.push(item);
       alert('添加成功');
       
    }
  }

四、效果展示

主页 


 显示学号尾号为单数的学生信息 


 增加学生信息

五、总结

虽然只是很小的一个 demo,但在完成中还是遇到了很多问题,比如要注意 v-show 和 v-if 的区别。一开始,本来想使用 v-show 来按筛选条件来显示不同的学生信息,但是发现就算不符合当前条件的学生信息还是被渲染并且显示出来了,通过寻求帮助,才发现如果我们要显示多个页面,并且这些页面是互斥的关系话,我们使用 v-if ,v-else-if,v-else 来显示。

以下是 v-show 和 v-if 的区别

v-if 只有在判断为 true 的时候才会对数据进行渲染,false 的时候把包含的代码进行删除。除非再次进行数据渲染,v-if 才会重新判断。可以说是用法比较倾向于对数据一次操作。 v-show 是无论判断是什么都会先对数据进行渲染,只是 false 的时候对节点进行display:none;的操作。所以再不重新渲染数据的情况下,改变数据的值可以使数据展示或隐藏。

联系我们