首页 文章 精选 留言 我的

精选列表

搜索[AIOps最佳实践],共10000篇文章
优秀的个人博客,低调大师

日志服务数据加工最佳实践: 日期时间处理

场景1:Unix时间戳、日期时间字符串和日期时间对象的相互转换 LOG DSL语法中的日期时间处理主要涉及三种数据类型:Unix时间戳、日期时间字符串和日期时间对象。它们的相互转换方式如下图: 子场景1:日期时间对象和Unix时间戳的相互转换 1)日期时间对象转为Unix时间戳 dt_parsetimestamp智能转换函数,可以将日期时间对象或日期时间字符串转化为Unix时间戳。 dt_totimestamp,只支持将日期时间对象转化为Unix时间戳。 2)Unix时间戳转为日期时间对象 dt_parse智能转换函数,可以将Unix时间戳或日期时间字符串转化为日期时间对象 dt_fromtimestamp,只支持将Unix时间戳转化为日期时间对象。 子场景2:日期时间对象和日期时间字符串的相互转换 1)日期时间对象转为日期时间字符串 dt_str智能

优秀的个人博客,低调大师

生产SparkStreaming数据零丢失最佳实践(含代码)

MySQL创建存储offset的表格 mysql> use test mysql> create table hlw_offset( topic varchar(32), groupid varchar(50), partitions int, fromoffset bigint, untiloffset bigint, primary key(topic,groupid,partitions) ); Maven依赖包 <scala.version>2.11.8</scala.version> <spark.version>2.3.1</spark.version> <scalikejdbc.version>2.5.0</scalikejdbc.version> -------------------------------------------------- <dependency> <groupId>org.scala-lang</groupId> <artifactId>scala-library</artifactId> <version>${scala.version}</version> </dependency> <dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-core_2.11</artifactId> <version>${spark.version}</version> </dependency> <dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-sql_2.11</artifactId> <version>${spark.version}</version> </dependency> <dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-streaming_2.11</artifactId> <version>${spark.version}</version> </dependency> <dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-streaming-kafka-0-8_2.11</artifactId> <version>${spark.version}</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.27</version> </dependency> <!-- https://mvnrepository.com/artifact/org.scalikejdbc/scalikejdbc --> <dependency> <groupId>org.scalikejdbc</groupId> <artifactId>scalikejdbc_2.11</artifactId> <version>2.5.0</version> </dependency> <dependency> <groupId>org.scalikejdbc</groupId> <artifactId>scalikejdbc-config_2.11</artifactId> <version>2.5.0</version> </dependency> <dependency> <groupId>com.typesafe</groupId> <artifactId>config</artifactId> <version>1.3.0</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.5</version> </dependency> 实现思路 1)StreamingContext 2)从kafka中获取数据(从外部存储获取offset-->根据offset获取kafka中的数据) 3)根据业务进行逻辑处理 4)将处理结果存到外部存储中--保存offset 5)启动程序,等待程序结束 代码实现 SparkStreaming主体代码如下 import kafka.common.TopicAndPartition import kafka.message.MessageAndMetadata import kafka.serializer.StringDecoder import org.apache.spark.SparkConf import org.apache.spark.streaming.kafka.{HasOffsetRanges, KafkaUtils} import org.apache.spark.streaming.{Seconds, StreamingContext} import scalikejdbc._ import scalikejdbc.config._ object JDBCOffsetApp { def main(args: Array[String]): Unit = { //创建SparkStreaming入口 val conf = new SparkConf().setMaster("local[2]").setAppName("JDBCOffsetApp") val ssc = new StreamingContext(conf,Seconds(5)) //kafka消费主题 val topics = ValueUtils.getStringValue("kafka.topics").split(",").toSet //kafka参数 //这里应用了自定义的ValueUtils工具类,来获取application.conf里的参数,方便后期修改 val kafkaParams = Map[String,String]( "metadata.broker.list"->ValueUtils.getStringValue("metadata.broker.list"), "auto.offset.reset"->ValueUtils.getStringValue("auto.offset.reset"), "group.id"->ValueUtils.getStringValue("group.id") ) //先使用scalikejdbc从MySQL数据库中读取offset信息 //+------------+------------------+------------+------------+-------------+ //| topic | groupid | partitions | fromoffset | untiloffset | //+------------+------------------+------------+------------+-------------+ //MySQL表结构如上,将“topic”,“partitions”,“untiloffset”列读取出来 //组成 fromOffsets: Map[TopicAndPartition, Long],后面createDirectStream用到 DBs.setup() val fromOffset = DB.readOnly( implicit session => { SQL("select * from hlw_offset").map(rs => { (TopicAndPartition(rs.string("topic"),rs.int("partitions")),rs.long("untiloffset")) }).list().apply() }).toMap //如果MySQL表中没有offset信息,就从0开始消费;如果有,就从已经存在的offset开始消费 val messages = if (fromOffset.isEmpty) { println("从头开始消费...") KafkaUtils.createDirectStream[String,String,StringDecoder,StringDecoder](ssc,kafkaParams,topics) } else { println("从已存在记录开始消费...") val messageHandler = (mm:MessageAndMetadata[String,String]) => (mm.key(),mm.message()) KafkaUtils.createDirectStream[String,String,StringDecoder,StringDecoder,(String,String)](ssc,kafkaParams,fromOffset,messageHandler) } messages.foreachRDD(rdd=>{ if(!rdd.isEmpty()){ //输出rdd的数据量 println("数据统计记录为:"+rdd.count()) //官方案例给出的获得rdd offset信息的方法,offsetRanges是由一系列offsetRange组成的数组 // trait HasOffsetRanges { // def offsetRanges: Array[OffsetRange] // } val offsetRanges = rdd.asInstanceOf[HasOffsetRanges].offsetRanges offsetRanges.foreach(x => { //输出每次消费的主题,分区,开始偏移量和结束偏移量 println(s"---${x.topic},${x.partition},${x.fromOffset},${x.untilOffset}---") //将最新的偏移量信息保存到MySQL表中 DB.autoCommit( implicit session => { SQL("replace into hlw_offset(topic,groupid,partitions,fromoffset,untiloffset) values (?,?,?,?,?)") .bind(x.topic,ValueUtils.getStringValue("group.id"),x.partition,x.fromOffset,x.untilOffset) .update().apply() }) }) } }) ssc.start() ssc.awaitTermination() } } 自定义的ValueUtils工具类如下 import com.typesafe.config.ConfigFactory import org.apache.commons.lang3.StringUtils object ValueUtils { val load = ConfigFactory.load() def getStringValue(key:String, defaultValue:String="") = { val value = load.getString(key) if(StringUtils.isNotEmpty(value)) { value } else { defaultValue } } } application.conf内容如下 metadata.broker.list = "192.168.137.251:9092" auto.offset.reset = "smallest" group.id = "hlw_offset_group" kafka.topics = "hlw_offset" serializer.class = "kafka.serializer.StringEncoder" request.required.acks = "1" # JDBC settings db.default.driver = "com.mysql.jdbc.Driver" db.default.url="jdbc:mysql://hadoop000:3306/test" db.default.user="root" db.default.password="123456" 自定义kafka producer import java.util.{Date, Properties} import kafka.producer.{KeyedMessage, Producer, ProducerConfig} object KafkaProducer { def main(args: Array[String]): Unit = { val properties = new Properties() properties.put("serializer.class",ValueUtils.getStringValue("serializer.class")) properties.put("metadata.broker.list",ValueUtils.getStringValue("metadata.broker.list")) properties.put("request.required.acks",ValueUtils.getStringValue("request.required.acks")) val producerConfig = new ProducerConfig(properties) val producer = new Producer[String,String](producerConfig) val topic = ValueUtils.getStringValue("kafka.topics") //每次产生100条数据 var i = 0 for (i <- 1 to 100) { val runtimes = new Date().toString val messages = new KeyedMessage[String, String](topic,i+"","hlw: "+runtimes) producer.send(messages) } println("数据发送完毕...") } } 测试 启动kafka服务,并创建主题 [hadoop@hadoop000 bin]$ ./kafka-server-start.sh -daemon /home/hadoop/app/kafka_2.11-0.10.0.1/config/server.properties [hadoop@hadoop000 bin]$ ./kafka-topics.sh --list --zookeeper localhost:2181/kafka [hadoop@hadoop000 bin]$ ./kafka-topics.sh --create --zookeeper localhost:2181/kafka --replication-factor 1 --partitions 1 --topic hlw_offset 测试前查看MySQL中offset表,刚开始是个空表 mysql> select * from hlw_offset; Empty set (0.00 sec) 通过kafka producer产生500条数据 启动SparkStreaming程序 //控制台输出结果: 从头开始消费... 数据统计记录为:500 ---hlw_offset,0,0,500--- 查看MySQL表,offset记录成功 mysql> select * from hlw_offset; +------------+------------------+------------+------------+-------------+ | topic | groupid | partitions | fromoffset | untiloffset | +------------+------------------+------------+------------+-------------+ | hlw_offset | hlw_offset_group | 0 | 0 | 500 | +------------+------------------+------------+------------+-------------+ 关闭SparkStreaming程序,再使用kafka producer生产300条数据,再次启动spark程序(如果spark从500开始消费,说明成功读取了offset,做到了只读取一次语义) //控制台结果输出: 从已存在记录开始消费... 数据统计记录为:300 ---hlw_offset,0,500,800--- 查看更新后的offset MySQL数据 mysql> select * from hlw_offset; +------------+------------------+------------+------------+-------------+ | topic | groupid | partitions | fromoffset | untiloffset | +------------+------------------+------------+------------+-------------+ | hlw_offset | hlw_offset_group | 0 | 500 | 800 | +------------+------------------+------------+------------+-------------+

优秀的个人博客,低调大师

Kubernetes Ingress 日志分析与监控的最佳实践

前言 目前Kubernetes(K8s)已经真正地占领了容器编排市场,是默认的云无关计算抽象,越来越多的企业开始将服务构建在K8s集群上。在K8s中,组件通过Service对外暴露服务,常见的包括NodePort、LoadBalancer、Ingress等。其中Ingress主要提供HTTP层(7层)路由功能,相比TCP(4层)的负载均衡具备非常多的优势(路由规则更加灵活、支持金丝雀、蓝绿、A/B Test发布模式、SSL支持、日志、监控、支持自定义扩展等),是目前K8s中HTTP/HTTPS服务的主流暴露方式。 Ingress简介 K8s中Ingress只是一种API资源的声明,具体的实现需要安装对应的Ingress Controller,由Ingress Controller接管Ingress定义,将流量转发到对应的Service。

优秀的个人博客,低调大师

技术篇-HBase 最佳实践-读性能优化策略

Full GC 问题之前在一些文章里面已经讲过它的来龙去脉,主要的解决方案目前 主要有两方面需要注意,一方面需要查看 GC 日志确认是哪种 Full GC,根据 Full GC 类型对 JVM 参数进行调优,另一方面需要确认是否开启了 BucketCache 的 offheap 模式,建议使用 LRUBlockCache 的童鞋尽快转移到 BucketCache 来。当然我们还是很期待官方 2.0.0 版本发布的更多 offheap 模块。 RIT 问题,我相信更多是因为我们对其不了解,具体原理可以戳这里,解决方案目前有两个,优先是使用官方提供的 HBCK 进行修复(HBCK 本人一直想拿出来分享,但是目前案例还不多,等后面有更多案例的话再拿出来说),使用之后还 是解决不了的话就需要手动修复文件或者元数据表。 而对于写吞吐量太低以及读

优秀的个人博客,低调大师

MSSQL · 最佳实践 · 使用混合密钥实现列加密

摘要 在SQL Server安全系列专题的上两期月报分享中,我们分别分享了:如何使用对称密钥实现SQL Server列加密技术和使用非对称密钥加密方式实现SQL Server列加密。本期月报我们分享使用混合密钥加密方式实现SQL Server列加密技术,最大限度减少性能损失,最大程度保护用户数据安全。 场景引入 对称加密是指加密和解密过程使用同一个密钥的加密算法,非对称加密是指加密和解密过程使用不同的密钥进行的加密算法。因此,通常来说对称加密安全性较弱,非对象加密安全性相对较高。凡事都具有两面性,非对称密钥加密的安全性较好,但通常算法相比对称密钥复杂许多,因此会带来性能上的损失也更大。有没有一种方法既可以最大限度保证数据安全性,又能够最大限度的减少性能损失呢?这便是本期月报分享的价值所在:SQL Server使用混合密钥实现列加密技术。

优秀的个人博客,低调大师

全面入门jQuery最佳实践(一)-选择器

1 初识JQuery 1.1 简介 1.2 环境搭建 进入官方网站获取最新的版本 http://jquery.com/download/ ,这里需要注意 jQuery 分 2 个系列版本 1.x 与 2.x,主要的区别在于 2.x 不再兼容 IE6、7、8浏览器,这样做的目的是为了兼容移动端开发。由于减少了一些代码,使得该版本比 jQuery 1.x 更小、更快。 如果开发者比较在意老版本 IE 用户,只能使用 jQuery 1.9 及之前的版本了。为了兼容性问题,使用的是 1.9 版本。jQuery 每一个系列版本分为:压缩版(compressed) 与 开发版(development),我们在开发过程中使用开发版(开发版本便于代码修改及调试),项目上线发布使用压缩版(因为压缩版本体积更小,效率更快)。 jQuery是一个JavaScript脚本库,不需要特别的安装,只需要我们在页面 <head> 标签内中,通过 script 标签引入 jQuery 库即可。 <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <script type="text/javascript" src="https://www.imooc.com/static/lib/jquery/1.9.1/jquery.js"></script> <title>环境搭建</title> </head> <body> <script type="text/javascript"> alert($) </script> </body> </html> 验证成功 1.3 jQueryHelloWorld体验 当页面加载完成后,在页面中以居中的方式显示“您好”字样。 代码分析$(document).ready 的作用是等页面的文档(document)中的节点都加载完毕后,再执行后续的代码,因为我们在执行代码的时候,可能会依赖页面的某一个元素,我们要确保这个元素真正的的被加载完毕后才能正确的使用。 1.4 jQuery对象与DOM对象 jQuery对象与DOM对象是不一样的 可能一时半会分不清楚哪些是jQuery对象,哪些是DOM对象,下面重点介绍一下jQuery对象,以及两者相互间的转换。 通过一个简单的例子,简单区分下jQuery对象与DOM对象: <p id=”sss”></p> 我们要获取页面上这个id为sss的p元素,然后给这个文本节点增加一段文字:“您好”,并且让文字颜色变成红色。 普通处理,通过标准JavaScript处理: var p = document.getElementById('sss'); p.innerHTML = '您好'; p.style.color = 'red'; 通过原生DOM模型提供的document.getElementById(“sss”) 获取的DOM元素就是一个DOM对象,再通过innerHTML与style属性处理文本与颜色。 jQuery的处理: var $p = $('#sss'); $p.html('您好').css('color','red'); 通过$('#sss')会得到一个$p的jQuery对象,$p是一个类数组对象。 这个对象里面包含了DOM对象的信息,然后封装了很多操作方法,调用自己的方法html与css,得到的效果与标准的JavaScript处理结果是一致的 通过标准的JavaScript操作DOM与jQuery操作DOM的对比,我们不难发现: 通过jQuery方法包装后的对象,是一个类数组对象。它与DOM对象完全不同,唯一相似的是它们都能操作DOM 通过jQuery处理DOM的操作,可以让开发者更专注业务逻辑的开发,而不需要我们具体知道哪个DOM节点有那些方法,也不需要关心不同浏览器的兼容性问题,我们通过jQuery提供的API进行开发,代码也会更加精短。 1.5 jQuery对象转化成DOM对象 jQuery库本质上还是JavaScript代码,它只是对JavaScript语言进行包装处理,为的是提供更好更方便快捷的DOM处理与开发中经常使用的功能。 我们使用jQuery的同时也能混合JavaScript原生代码一起使用。在很多场景中,我们需要jQuery与DOM能够相互的转换,它们都是可以操作的DOM元素,jQuery是一个类数组对象,而DOM对象就是一个单独的DOM元素。 如何把jQuery对象转成DOM对象? 利用数组下标的方式读取到jQuery中的DOM对象 用jQuery找到所有的div元素(3个),因为jQuery对象也是一个数组结构,可以通过数组下标索引找到第一个div元素,通过返回的div对象,调用它的style属性修改第一个div元素的颜色 通过jQuery的get() 允许我们直接访问jQuery对象中相关的DOM节点,get方法中提供一个元素的索引: 其实我们翻开源码,看看就知道了,get方法就是利用的第一种方式处理的,只是包装成一个get让开发者更直接方便的使用。 1.6 DOM对象转化成jQuery对象 $(参数)是一个多功能的方法 参数是一个DOM对象,jQuery方法会把这个DOM对象给包装成一个新的jQuery对象 通过$(dom)将普通的dom对象加工成jQuery对象之后,我们就可以调用jQuery的方法了 JavaScript代码 通过 getElementsByTagName获取到所有div节点的元素,结果是一个dom集合对象,不过这个对象是一个数组集合(3个div元素) 通过$(div)方法转化成jQuery对象,通过调用jQuery对象中的first与css方法查找第一个元素并且改变其颜色 2 jQuery选择器 2.1 id选择器 id选择器:一个用来查找的ID,即元素的id属性$( "#id" ) id选择器也是基本的选择器,jQuery内部使用JS函数document.getElementById()来处理ID的获取。 原生语法的支持总是非常高效的,所以在操作DOM的获取上,如果能采用id的话尽然考虑用这个选择器 id是唯一的,每个id值在一个页面中只能使用一次。如果多个元素分配了相同的id,将只匹配该id选择集合的第一个DOM元素 2.2 类选择器 通过class样式类名来获取节点$( ".class" ) 相对id选择器来说,效率相对会低一点,但是优势就是可以多选 同样的jQuery在实现上,对于类选择器,如果浏览器支持,jQuery使用JavaScript的原生getElementsByClassName()函数来实现的 右边实现一个原生getElementsByClassName()函数的实现代码与jQuery实现代码的比较 jQuery除了选择上的简单,而且没有再次使用循环处理 不难想到$(".SSS").css()方法内部肯定是带了一个隐式的循环处理,所以使用jQuery选择节点,不仅仅只是选择上的简单,同时还增加很多关联的便利操作 2.3 元素选择器 根据给定(HTML)标记名称选择所有的元素$( "element" ) 搜索指定元素标签名的所有节点,这个是一个合集的操作,原生方法getElementsByTagName() 第一组:通过getElementsByTagName得到页面所有的<div>var divs = document.getElementsByTagName('div'); divs是dom合集对象,通过循环给每一个合集中的<div>元素赋予新的border样式 第二组:同样的效果,$("p")选取所有的<p>元素,通过css方法直接赋予样式 2.4 全选择器(*选择器) 在CSS中,经常会在第一行写下这样一段样式 * {padding: 0; margin: 0;} 通配符意味着给所有的元素设置默认的边距。jQuery中我们也可以通过传递选择器来选中文档页面中的元素$( "*" ) 抛开jQuery,如果要获取文档中所有的元素,通过document.getElementsByTagName()中传递"*"同样可以获取到 id、class、tag都可以通过原生的方法获取到对应的节点,但还需考虑一个兼容性问题,这里顺便提及一下,比如 IE会将注释节点实现为元素,所以在IE中调用getElementsByTagName会包含注释节点,这个通常是不应该的 getElementById的参数在<=IE8不区分大小写 <=IE7中,表单元素中,如果表单A的name属性名用了另一个元素B的ID名并且A在B之前,那么getElementById会选中A <=IE8,浏览器不支持getElementsByClassName 幸好有jQuery的出现,让我们省了很多功夫 2.5 层级选择器 文档中的所有的节点之间都是有这样或者那样的关系 我们可以把节点之间的关系可以用传统的家族关系来描述,把文档树当作一个家谱,那么节点与节点直接就会存在父子,兄弟,祖孙的关系了。 选择器中的层级选择器就是用来处理这种关系 对比层级选择器的区别 层级选择器都有一个参考节点 后代选择器包含子选择器的选择的内容 一般兄弟选择器包含相邻兄弟选择的内容 相邻兄弟选择器和一般兄弟选择器所选择到的元素,必须在同一个父元素下 2.6 基本筛选选择器 筛选选择器很多都不是CSS的规范,而是jQuery自己为了开发者的便利延展出来的选择器 筛选选择器的用法与CSS中的伪元素相似 :eq(), :lt(), :gt(), :even, :odd 用来筛选他们前面的匹配表达式的集合元素,根据之前匹配的元素在进一步筛选,注意jQuery合集都是从0开始索引 gt是一个段落筛选,从指定索引的下一个开始,gt(1) 实际从2开始 2.7 内容筛选选择器 基本筛选选择器针对的都是元素DOM节点 如果我们要通过内容来过滤,jQuery也提供了一组内容筛选选择器 :contains与:has都有查找的意思,但是contains查找包含“指定文本”的元素,has查找包含“指定元素”的元素 如果:contains匹配的文本包含在元素的子元素中,同样认为是符合条件的。 :parent与:empty是相反的,两者所涉及的子元素,包括文本节点 2.8 可见性筛选选择器 元素可见性依赖于适用的样式 我们有几种方式隐藏一个元素 CSS display的值是none。 type="hidden"的表单元素。 宽度和高度都显式设置为0。 一个祖先元素是隐藏的,该元素是不会在页面上显示 CSS visibility的值是hidden CSS opacity的指是0 如果元素中占据文档中一定的空间,元素被认为是可见的。 可见元素的宽度或高度,是大于零。 元素的visibility: hidden 或 opacity: 0被认为是可见的,因为他们仍然占用空间布局 不在文档中的元素是被认为是不可见的,如果当他们被插入到文档中,jQuery没有办法知道他们是否是可见的,因为元素可见性依赖于适用的样式 2.9 属性筛选选择器 基于属性来定位一个元素 可只指定该元素的某个属性,这样只需使用该属性而不管它的值,这个元素都将被定位,也可以更加明确并定位在这些属性上使用特定值的元素 浏览器支持 [att=val]、[att]、[att|=val]、[att~=val] 属于CSS 2.1规范 [ns|attr]、[att^=val]、[att*=val]、[att$=val] 属于CSS3规范 [name!="value"] 属于jQuery 扩展的选择器 CSS选择器无论CSS2.1版本还是CSS3版本,IE7和IE8都支持,webkit、Gecko核心及Opera也都支持,只有IE6以下浏览器才不支持 在这么多属性选择器中[attr="value"]和[attr*="value"]是最实用的 [attr="value"]能帮我们定位不同类型的元素,特别是表单form元素的操作,比如说input[type="text"],input[type="checkbox"]等 [attr*="value"]能在网站中帮助我们匹配不同类型的文件 2.10 元素筛选选择器 子元素筛选选择器不常使用,其筛选规则比起其它的选择器稍微要复杂点 :first只匹配一个单独的元素,但:first-child可匹配多个:为每个父级元素匹配第一个子元素。相当于:nth-child(1) :last 只匹配一个单独的元素,:last-child 选择器可以匹配多个元素:为每个父级元素匹配最后一个子元素 如果子元素只有一个的话,:first-child与:last-child是同一个 :only-child匹配某个元素是父元素中唯一的子元素,就是说当前子元素是父元素中唯一的元素,则匹配 jQuery实现:nth-child(n)是严格来自CSS规范,所以n值是“索引”,也就是说,从1开始计数,:nth-child(index)从1开始的,而eq(index)是从0开始的 nth-child(n) 与:nth-last-child(n)的区别是前者从前往后计算,后者从后往前 2.11 表单元素选择器 jQuery中专门加入了表单选择器,从而能够极其方便地获取到某个类型的表单元素 除了input筛选选择器,几乎每个表单类别筛选器都对应一个input元素的type值 大部分表单类别筛选器可以使用属性筛选器替换 比如 $(':password') == $('[type=password]') 2.13 表单对象属性筛选选择器 附加在其他选择器的后面,主要功能是对所选择的表单元素进行筛选 选择器适用于复选框和单选框,对于下拉框元素, 使用 :selected 在某些浏览器中,:checked可能会错误选取到<option>,所以保险起见换用input:checked,确保只会选取<input> 2.14 特殊选择器this $(this)和this有什么区别呢? this是JavaScript中的关键字,指的是当前的上下文对象,简单的说就是方法/属性的所有者 下面例子中,imooc是一个对象,拥有name属性与getName方法,在getName中this指向了所属的对象imooc var imooc = { name:"慕课网", getName:function(){ //this,就是imooc对象 return this.name; } } imooc.getName(); //慕课网 this是动态的,这个上下文对象都是可以被动态改变的(可以通过call,apply等方法) 同样的在DOM中this就是指向了这个html元素对象,因为this就是DOM元素本身的一个引用 假如给页面一个P元素绑定一个事件: p.addEventListener('click',function(){ //this === p //以下两者的修改都是等价的 this.style.color = "red"; p.style.color = "red"; },false); 通过addEventListener绑定的事件回调中,this指向的是当前的dom对象,所以再次修改这样对象的样式,只需要通过this获取到引用即可 this.style.color = "red" 但是这样的操作其实还是很不方便的,这里面就要涉及一大堆的样式兼容,如果通过jQuery处理就会简单多了,我们只需要把this加工成jQuery对象 换成jQuery的做法: $('p').click(function(){ //把p元素转化成jQuery的对象 var $this= $(this) $this.css('color','red') }) 通过把$()方法传入当前的元素对象的引用this,把这个this加工成jQuery对象,我们就可以用jQuery提供的快捷方法直接处理样式了 总体: this,表示当前的上下文对象是一个html对象,可以调用html对象所拥有的属性和方法。 $(this),代表的上下文对象是一个jquery的上下文对象,可以调用jQuery的方法和属性值。 2.12 综合案例 <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title>jQuery标签切换效果</title> <link rel="stylesheet" href="imooc.css" type="text/css"> <script src="http://libs.baidu.com/jquery/1.9.1/jquery.js"></script> </head> <body> <!--代码部分begin--> <div id="menu"> <!--tag标题--> <div id="menu_female"> <h3>女装</h3> <div class="tag" style="display: block;"> <dl> <dd> <p>第一类</p> <a>1.衬衫</a> <a>2.T恤</a> <a>3.雪纺衫</a> <a>4.针织衫</a> <a>5.短外套</a> <a>6.卫衣</a> <a>7.小西裤</a> <a>8.风衣</a> <a>9.吊带背心</a> <a>10.连衣裙</a> <a name="setColor">11.蕾丝连衣裙</a> <a>12.复古连衣裙</a> <a>13.印花连衣裙</a> <a>14.真丝连衣裙</a> <a>更多</a> </dd> </dl> </div> <div class="tag_More" style="display:block"> <dl> <dd> <p>第二类</p> <a>1.背带裤</a> <a>2.哈伦裤</a> <a>3.牛仔裤</a> <a>4.休闲裤</a> <a>5.小脚裤</a> <a>6.西装裤</a> <a>7.打底裤</a> <a>8.阔脚裤</a> <a>9.短裤</a> <a>10.马甲/背心</a> <a>11.羽绒服</a> <a>12.棉服</a> <a>13.夹克</a> <a>14.POLO衫</a> <a>更多</a> </dd> </dl> </div> > </div> <div id="menu_con"> <h3>男装</h3> <div class="tag" style="display:block"> <dl> <dd> <p>第一类</p> <a>1.衬衫</a> <a>2.T恤</a> <a>3.牛仔裤</a> <a>4.休闲裤</a> <a>5.短裤</a> <a>6.针织衫</a> <a>7.西服</a> <a>8.西裤</a> <a>9.嘻哈裤</a> <a>10.西服套装</a> <a>11.马甲/背心</a> <a name="setColor">12.羽绒服</a> <a>13.棉服</a> <a>14.夹克</a> <p>更多</p> </dd> </dl> </div> <div class="tag_More" style="display:block"> <dl> <dd> <p>第二类</p> <a>1.衬衫</a> <a>2.T恤</a> <a>3.牛仔裤</a> <a name='setColor'>4.休闲裤</a> <a>5.短裤</a> <a>6.针织衫</a> <a>7.西服</a> <a>8.西裤</a> <a>9.嘻哈裤</a> <a>10.西服套装</a> <a>11.马甲/背心</a> <a>12.羽绒服</a> <a>13.棉服</a> <a>14.夹克</a> <p>更多</p> </dd> </dl> </div> > </div> </div> <script type="text/javascript"> //找到男装下第一类衣服中的第一个p元素,并改变颜色 //可以通过子类选择器 p:first-child 筛选出第一个p元素 $("#menu_con .tag p:first").css('color', '#9932CC'); </script> <script type="text/javascript"> //找到男装下第一类衣服把a元素从顺序1-4加上颜色 //可以通过基本筛选器lt,选择匹配集合中所有索引值小于给定index参数的元素 //注意了index是从0开始计算,所以选在1-4,为对应的index就是4 $("#menu_con .tag a:lt(4)").css('color', 'red'); </script> <script type="text/javascript"> //找到男装所有a元素中属性名name="setColor"的元素,并设置颜色 //这里用的属性选择器[attribute='value']选择指定属性是给定值的元素 $("#menu_con a[name='setColor']").css('color', 'blue'); </script> <script type="text/javascript"> //不分男女,选中第一类衣服中第9个a元素,并改变颜色 //这里用了nth-child 选择的他们所有父元素的第n个子元素 $("#menu .tag a:nth-child(10)").css('color', '#66CD00'); </script> <script type="text/javascript"> //找到女装下第一类衣服,把a元素中包含文字"更多"的节点,改变颜色 $("#menu_female .tag a:contains('更多')").css('color', '#C71585'); </script> </body> </html>

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册