以下是 html5双击选中文字高亮显示特效代码 的示例演示效果:
部分效果截图:
HTML代码(index.html):
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>html5˫��ѡ�����ָ�����ʾ</title>
<meta name="viewport" content="width=800, user-scalable=no">
<link rel="stylesheet" href="css/demo.css" type="text/css" />
</head>
<body>
<div class="intro">
<article>
<h1>Fokus</h1>
<p>
Fokus uses JavaScript to emphasize anything you select by covering the rest of the page with semi-transparent black.
</p>
<p>
Try it out by selecting this paragraph or the sample content below. You'll see the entire page fade out while this text is highlighted.
</p>
<p>
If you want to use Fokus on your site you just need to include the fokus.min.js script (3kb, no dependencies).
</p>
<p>
Fokus is also available as a Chrome extension.
</p>
</article>
</div>
<script src="js/fokus.min.js"></script>
</body>
</html>
JS代码(fokus.js):
/*! * Fokus 0.5 * http://lab.hakim.se/fokus * MIT licensed * * Copyright (C) 2012 Hakim El Hattab,http://hakim.se */
(function(){
// Padding around the selectionvar PADDING = 5;
// Opacity of the overlayvar OPACITY = 0.75;
// Key modifier that needs to be held down for overlay to appearvar MODIFIER = null;
// The opaque overlay canvasvar overlay,overlayContext,overlayAlpha = 0,// Reference to the redraw animation so it can be cancelledredrawAnimation,// Currently selected regionselectedRegion ={
left:0,top:0,right:0,bottom:0}
,// Currently cleared regionclearedRegion ={
left:0,top:0,right:0,bottom:0}
,// Currently pressed down key modifierskeyModifiers ={
ctrl:false,shift:false,alt:false,cmd:false}
;
// choo choo!function initialize(){
// Only initialize if the client is capableif( capable() && !window.__fokused ){
// Ensures that Fokus isn't initialized twice on the same pagewindow.__fokused = true;
overlay = document.createElement( 'canvas' );
overlayContext = overlay.getContext( '2d' );
// Place the canvas on top of everythingoverlay.style.position = 'fixed';
overlay.style.left = 0;
overlay.style.top = 0;
overlay.style.zIndex = 2147483647;
overlay.style.pointerEvents = 'none';
overlay.style.background = 'transparent';
document.addEventListener( 'mousedown',onMouseDown,false );
document.addEventListener( 'keyup',onKeyPress,false );
document.addEventListener( 'keydown',onKeyPress,false );
document.addEventListener( 'scroll',onScroll,false );
document.addEventListener( 'DOMMouseScroll',onScroll,false );
window.addEventListener( 'resize',onWindowResize,false );
// Trigger an initial resizeonWindowResize();
}
}
/** * Is this browser capable of running Fokus? */
function capable(){
return !!('addEventListener' in document &&'pointerEvents' in document.body.style);
}
/** * Redraws an animates the overlay. */
function redraw(){
// Cache the response of this for re-use belowvar _hasSelection = hasSelection();
// Reset to a solid (less opacity) overlay filloverlayContext.clearRect( 0,0,overlay.width,overlay.height );
overlayContext.fillStyle = 'rgba( 0,0,0,'+ overlayAlpha +' )';
overlayContext.fillRect( 0,0,overlay.width,overlay.height );
if( _hasSelection ){
if( overlayAlpha < 0.1 ){
// Clear the selection instantly if we're just fading inclearedRegion = selectedRegion;
}
else{
// Ease the cleared region towards the selected selectionclearedRegion.left += ( selectedRegion.left - clearedRegion.left ) * 0.18;
clearedRegion.top += ( selectedRegion.top - clearedRegion.top ) * 0.18;
clearedRegion.right += ( selectedRegion.right - clearedRegion.right ) * 0.18;
clearedRegion.bottom += ( selectedRegion.bottom - clearedRegion.bottom ) * 0.18;
}
}
// Cut out the cleared regionoverlayContext.clearRect(clearedRegion.left - window.scrollX - PADDING,clearedRegion.top - window.scrollY - PADDING,( clearedRegion.right - clearedRegion.left ) + ( PADDING * 2 ),( clearedRegion.bottom - clearedRegion.top ) + ( PADDING * 2 ));
// Fade in if there's a valid selection...if( _hasSelection ){
overlayAlpha += ( OPACITY - overlayAlpha ) * 0.08;
}
// ... otherwise fade outelse{
overlayAlpha = Math.max( ( overlayAlpha * 0.85 ) - 0.02,0 );
}
// Ensure there is no overlapcancelAnimationFrame( redrawAnimation );
// Continue so long as there is content selected or we are fading outif( _hasSelection || overlayAlpha > 0 ){
// Append the overlay if it isn't already in the DOMif( !overlay.parentNode ) document.body.appendChild( overlay );
// Stage a new animation frameredrawAnimation = requestAnimationFrame( redraw );
}
else{
document.body.removeChild( overlay );
}
}
/** * Steps through all selected nodes and updates the selected * region (bounds of selection). * * @param{
Boolean}
immediate flags if selection should happen * immediately,defaults to false which means the selection * rect animates into place */
function updateSelection( immediate ){
// Default to negative spacevar currentRegion ={
left:Number.MAX_VALUE,top:Number.MAX_VALUE,right:0,bottom:0}
;
var nodes = getSelectedNodes();
for( var i = 0,len = nodes.length;
i < len;
i++ ){
var node = nodes[i];
// Select parents of text nodes that have contentsif( node.nodeName === '#text' && node.nodeValue.trim() ){
node = node.parentNode;
}
// Fetch the screen coordinates for this elementvar position = getScreenPosition( node );
var x = position.x,y = position.y,w = node.offsetWidth,h = node.offsetHeight;
// 1. offsetLeft works// 2. offsetWidth works// 3. Element is larger than zero pixels// 4. Element is not <br>if( node && typeof x === 'number' && typeof w === 'number' && ( w > 0 || h > 0 ) && !node.nodeName.match( /^br$/gi ) ){
currentRegion.left = Math.min( currentRegion.left,x );
currentRegion.top = Math.min( currentRegion.top,y );
currentRegion.right = Math.max( currentRegion.right,x + w );
currentRegion.bottom = Math.max( currentRegion.bottom,y + h );
}
}
// Don't update selection if a modifier is specified but not// pressed down,unless there's already a selected regionif( !MODIFIER || MODIFIER === 'none' || keyModifiers[ MODIFIER ] || hasSelection() ){
selectedRegion = currentRegion;
}
// If flagged,update the cleared region immediatelyif( immediate ){
clearedRegion = selectedRegion;
}
// Start repainting if there is a selected regionif( hasSelection() ){
redraw();
}
}
/** * Checks if a region is currently selected. */
function hasSelection(){
return selectedRegion.left < selectedRegion.right && selectedRegion.top < selectedRegion.bottom;
}
function onMouseDown( event ){
// Don't start selection on right clickif( event.which !== 3 ){
document.addEventListener( 'mousemove',onMouseMove,false );
document.addEventListener( 'mouseup',onMouseUp,false );
updateSelection();
}
}
function onMouseMove( event ){
updateSelection();
}
function onMouseUp( event ){
document.removeEventListener( 'mousemove',onMouseMove,false );
document.removeEventListener( 'mouseup',onMouseUp,false );
setTimeout( updateSelection,1 );
}
function onKeyPress( event ){
keyModifiers.alt = event.altKey || event.altGraphKey;
keyModifiers.ctrl = event.ctrlKey;
keyModifiers.shift = event.shiftKey;
keyModifiers.meta = event.metaKey;
updateSelection();
}
function onScroll( event ){
updateSelection( true );
}
/** * Make sure the overlay canvas is always as wide and tall as * the current window. */
function onWindowResize( event ){
overlay.width = window.innerWidth;
overlay.height = window.innerHeight;
}
/** * Helper methods for getting selected nodes,source:* http://stackoverflow.com/questions/7781963/js-get-array-of-all-selected-nodes-in-contenteditable-div */
function getSelectedNodes(){
if (window.getSelection){
var sel = window.getSelection();
if (!sel.isCollapsed){
return getRangeSelectedNodes(sel.getRangeAt(0));
}
}
return [];
}
function getRangeSelectedNodes( range ){
var node = range.startContainer;
var endNode = range.endContainer;
// Special case for a range that is contained within a single nodeif (node == endNode){
if( node.nodeName === '#text' ){
return [node.parentNode];
}
return [node];
}
// Iterate nodes until we hit the end containervar rangeNodes = [];
while (node && node != endNode){
rangeNodes.push( node = nextNode(node) );
}
// Add partially selected nodes at the start of the rangenode = range.startContainer;
while (node && node != range.commonAncestorContainer){
rangeNodes.unshift(node);
node = node.parentNode;
}
return rangeNodes;
}
function nextNode(node){
if (node.hasChildNodes()){
return node.firstChild;
}
else{
while (node && !node.nextSibling){
node = node.parentNode;
}
if (!node){
return null;
}
return node.nextSibling;
}
}
/** * Gets the x/y screen position of the target node,source:* http://www.quirksmode.org/js/findpos.html */
function getScreenPosition( node ){
var x = document.documentElement.offsetLeft,y = document.documentElement.offsetTop;
if ( node.offsetParent ){
do{
x += node.offsetLeft;
y += node.offsetTop;
}
while ( node = node.offsetParent );
}
return{
x:x,y:y}
;
}
/** * rAF polyfill. */
(function(){
var lastTime = 0;
var vendors = ['ms','moz','webkit','o'];
for(var x = 0;
x < vendors.length && !window.requestAnimationFrame;
++x){
window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame)window.requestAnimationFrame = function(callback,element){
var currTime = new Date().getTime();
var timeToCall = Math.max(0,16 - (currTime - lastTime));
var id = window.setTimeout(function(){
callback(currTime + timeToCall);
}
,timeToCall);
lastTime = currTime + timeToCall;
return id;
}
;
if (!window.cancelAnimationFrame)window.cancelAnimationFrame = function(id){
clearTimeout(id);
}
;
}
());
initialize();
}
)();
CSS代码(demo.css):
/*** Styles for the Fokus demo page.* * @author Hakim El Hattab | http://hakim.se*/
*{margin:0;padding:0;}
::selection{background:#d1edf8;}
html,body{height:100%;}
body{background:#eee;font-family:'Lato',Helvetica,sans-serif;font-size:16px;color:#222;}
a{color:#c2575b;text-decoration:none;-webkit-transition:0.15s color ease;-moz-transition:0.15s color ease;-ms-transition:0.15s color ease;-o-transition:0.15s color ease;transition:0.15s color ease;}
a:hover{color:#f76f76;}
h1,h2{font-size:24px;}
/* intro */
.intro{display:inline-block;background:#eee;padding:40px 60px;overflow-y:auto;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;}
.intro h1{position:relative;}
.intro h1:after{content:'';position:absolute;display:inline-block;width:48px;height:48px;top:-9px;margin-left:7px;background-image:url( 'fokus48.png' );background-repeat:no-repeat;}
.intro>article{width:400px;}
.intro p{margin:10px 0 10px 0;font-size:16px;line-height:1.5em;}
.intro small{display:block;margin-top:10px;padding-top:10px;color:#333;font-size:0.85em;border-top:1px dashed #ccc;-webkit-text-size-adjust:none;}
.intro .sharing{margin-top:20px;}