This is the source code of the js scrolling plug-in I wrote during the Chinese New Year. I am not satisfied with the results of the results. I went back to consolidate and learn js in depth. This plug-in has the following unsatisfactory aspects:
For excessive effects of the content, you can refer to the scrollbar in the recent session list of the QQ client. Its scrolling is very smooth, simply put, it lacks animation transition effects.
Not perfect compatibility, the style under IE6 and 7 is still a bit flawed.
The style is imperfect, such as the scroll bar is displayed only when the mouse is suspended, and the effect hidden after removal is not written.
The internal structure is confusing, and the content structure needs to be adjusted.
The scroll bar picture is not an artist after all, and it is so disgusting to cut the picture by yourself...
Overall, it is still possible to watch, but there is still a lack of an animation. When I wrote this plug-in, I realized that my plug-in used some relatively basic functions, so I thought that these functions should be encapsulated. I have been studying js in depth recently. After reading the book at hand, I should start writing this basic function plug-in. Of course, an animation engine is indispensable. Without further ado, the source code is here (note: the complete version of this plug-in has pictures, please download the complete plug-in in the attachment at the end of the article):
CSS
The code copy is as follows:
.lf_Scroll, .lf_Scroll li { padding: 0; margin: 0; list-style: none; font: 14px/24px "Helvetica Neue" ,Helvetica,Arial, 'Microsoft Yahei' ,sans-serif; outline: none; }
.lf_Scroll { cursor: pointer; width: 10px; position: absolute; right: 0; top: 0; filter: alpha(opacity=50); -moz-opacity: 0.5; -khtml-opacity: 0.5; opacity: 0.5; }
.lf_ScrollFocus { filter: alpha(opacity=100); -moz-opacity: 1; -khtml-opacity: 1; opacity: 1; }
.lfs_Top, .lfs_Center, .lfs_Bottom { background: url('ScrollBar.gif'); width: 10px; height: 10px; }
.lfs_Top { background-position: 1px 0px; }
.lfs_Center { background-position: center 0; height: 100px; }
.lfs_Bottom { background-position: -22px 0; }
/*Developers config*/
.rollDiv { height: 100%; width: 100%; overflow: hidden; position: relative; }
JavaScript
The code copy is as follows:
/*
* This plugin is defined on the simulation Webpage scroll bar, please insert after binding for DOM events
*
* Comment version: 1.0.0
* Author: linkfly
* Sina: Focus on half a century for you | cnblogs: http://www.cnblogs.com/silin6/ | Email:[email protected]
* date:2014-02-05 02:38:35
*
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
*/
(function (window, undefined) {
//Configuration parameter information
var config = {
auto: true,
height: 'auto',
width: 'auto'
};
var linkFlyScroll = function (dom, options) {
/// <summary>
/// 1: Generate a simulated scrollbar object, [Please bind events to the object specified after this object works, otherwise the events you bound previously will not work]
/// 1.1 - linkFlyScroll(dom) - Generate scrollbar object on the specified dom
/// 1.2 - linkFlyScroll(dom,options) - Generate scrollbar objects, and provide a series of parameters that allow you to customize the working model for configuring the object.
/// </summary>
/// <param name="dom" type="String Or element">
/// Pass in js dom object, or the object ID of type string
/// </param>
/// <param name="options" type="Json">
/// Customize the working model of this object, with the following options:
/// [Optional] auto (Boolean): When the content does not reach the height of the container, will the scroll bar be automatically hidden? The default is true (yes)
/// [Optional]height (Int Or String): The default unit is px, which can be int and String. If the value is auto, the height of css is used by default.
/// [Optional] width (Int Or String): The default unit is px, which can be int and String. If the value is auto, the width of css is used by default.
/// </param>
/// <returns type="linkFlyScroll" />
if (typeof (dom) === 'string') {
dom = document.getElementById(dom);
}
//No dom specified and no valid dom found
//linkFlyScroll(""), linkFlyScroll(null), linkFlyScroll(undefined)
if (!dom || !dom.nodeType)
return this;
//Create container object
var scrollObj = document.createElement('div');
//The content object is deeply cloned and does not contain events, so you need to wait until the linkFlyScroll object is finished working before you can bind events to the dom object.
var cloneObj = dom.cloneNode(true);
scrollObj.className = 'rollDiv';
scrollObj.appendChild(cloneObj);
//Replace the current object on the page
dom.parentNode.replaceChild(scrollObj, dom);
return new linkFlyScroll.prototype.init(scrollObj, options ? options : {});
};
linkFlyScroll.prototype.init = function (dom, options) {
/// <summary>
/// 1: This object is the real object. The special way of working is because there may be static calls and instantiated calls of linkFlyScroll
/// 1.1 - init(dom,options) - Generate scrollbar object on the specified dom
/// </summary>
/// <param name="dom" type="element">
/// dom object
/// </param>
/// <param name="options" type="Json">
/// Customize the working model of this object, with the following options:
/// [Optional] auto (Boolean): When the content does not reach the height of the container, will the scroll bar be automatically hidden? The default is true (yes)
/// [Optional]height (Int Or String): The default unit is px, which can be int and String. If the value is auto, the height of css is used by default.
/// [Optional] width (Int Or String): The default unit is px, which can be int and String. If the value is auto, the width of css is used by default.
/// </param>
/// <returns type="linkFlyScroll" />
/*
* This object contains the following properties:
* isDrag: Is the scrollbar being dragged
* startTop: (Working) Scroll bar start scrolling position
* endTop: (Working) scroll bar end scroll position
* topLimit: Top Limit position of scroll bar
* bottomLimit: the limit position at the bottom of the scroll bar
* context:Content Dom
* scrollRadix: scrolling cardinality
* target:Container Dom
*/
//The current this object, in order to prevent this pointer from changing frequently in the environment (for example, when binding events), save the current object.
var currScroll = this;
//DOMElement
if (dom.nodeType) {
//Save container and content DOM
currScroll.target = dom;
currScroll.context = dom.firstChild;
//Merge configuration parameters
currScroll.options = tool.extend(config, options);
if (currScroll.options.width !== 'auto') {
dom.style.width = tool.convertValue(currScroll.options.width);
}
if (currScroll.options.height !== 'auto') {
dom.style.height = tool.convertValue(currScroll.options.height);
}
//Find a valid dom
while (currScroll.context.nodeType != 1) {
currScroll.context = currScroll.context.nextSibling;
}
//Create scrollbar dom
currScroll.scrollUl = document.createElement('ul');
currScroll.scrollUl.className = 'lf_Scroll';
currScroll.scrollUl.appendChild(tool.setClass('li', 'lfs_Top'));
currScroll.scrollUl.appendChild(tool.setClass('li', 'lfs_Center'));
currScroll.scrollUl.appendChild(tool.setClass('li', 'lfs_Bottom'));
currScroll.context.style.position = 'relative';
//Present on the page before you can read the location data
dom.appendChild(currScroll.scrollUl);
this.change();
tool.addScrollEvent(currScroll.context, function (e) {
//Bind mouse wheel event, 3px scrolling unit
if (e.wheel > 0) {//The scroll wheel scrolls upward
var currTop = currScroll.endTop -= 3;
currScroll.scrollEvent.call(currScroll, currTop);
} else {//The scroll wheel scrolls down
var currTop = currScroll.endTop += 3;
currScroll.scrollEvent.call(currScroll, currTop);
}
});
//The prohibited text is selected when dragging TODO
// Click the event under the mouse and you need to determine whether it is a left-click. Currently, the right-click will also realize scrolling TODO.
tool.addEvent(currScroll.scrollUl, 'mousedown', function (e) {
mouseDown.call(currScroll, e);
});
//Add events to implement monitoring on body for better user experience
tool.addEvent(document.body, 'mousemove', function (e) {
if (currScroll.isDrag) {
//Get the current mouse position
var position = tool.getMousePos(e);
//The current scroll bar top position
var currTop = (currScroll.endTop + position.y - currScroll.startTop);
//Call is to make this pointer point to this working object accurately
currScroll.scrollEvent.call(currScroll, currTop);
}
return false;
});
//Add a mouse release event, and listen on the body in order to accurately capture the release event
tool.addEvent(document.body, 'mouseup', function () {
mouseUp.call(currScroll, []);
});
var mouseDown = function (e) {
/// <summary>
/// 1: Mouse press event
/// 1.1 - mouseDown(e) - MouseDown event in the scrollbar press
/// </summary>
/// <param name="e" type="Event">
/// Event object
/// </param>
/// <returns type="linkFlyScroll" />
currScroll.isDrag = true;
//Get the current mouse y position
currScroll.startTop = tool.getMousePos(e).y;
tool.addClass(currScroll.scrollUl, 'lf_ScrollFocus');
return false;
};
var mouseUp = function () {
/// <summary>
/// 1: Mouse release event
/// 1.1 - mouseUp() - MouseUp() - Release scrollbar event in the scrollbar
/// </summary>
/// <returns type="linkFlyScroll" />
currScroll.isDrag = false;
currScroll.endTop = currScroll.scrollUl.style.top ? parseInt(currScroll.scrollUl.style.top) : 0;
tool.removeClass(currScroll.scrollUl, 'lf_ScrollFocus');
return false;
};
currScroll.scrollEvent = function (currTop) {
/// <summary>
/// 1: Scroll event (core), just pass in the coordinates that need to be scrolled (scroll bar top)
/// 1.1 - scrollEvent(currTop) - Core scroll event
/// </summary>
/// <param name="currTop" type="Int">
/// The top value of the top of the scroll bar is from the previous layer of the container
/// </param>
/// <returns type="void" />
if (currTop <= currScroll.topLimit || currTop < 0) {//Top limit
currTop = currScroll.topLimit;
} else if (currTop >= currScroll.bottomLimit) {//Bottom Limit
currTop = currScroll.bottomLimit;
}
//Scrollbar offset effect
currScroll.scrollUl.style.top = currTop + 'px';
var tempTop = parseInt(currScroll.context.style.top? currScroll.context.style.top: 0);
//debug code
// document.getElementById('postionInfo').innerHTML = 'currTop:' + currTop + ' scrolling cardinality:' + currScroll.scrollRadix + ' bottomLimit:' + currScroll.bottomLimit + ' endTop:' + currScroll.endTop + ' startTop:' + currScroll.startTop + " Y:" + currTop + " offsetTop:" + currScroll.scrollUl.offsetTop + "compute:" + (currTop * currScroll.scrollRadix * -1) + 'px';
//text code
//Content scrolling: The current scroll bar top* cardinality takes negative number
currScroll.context.style.top = currTop * currScroll.scrollRadix * -1 + 'px';
};
return currScroll;
};
};
linkFlyScroll.prototype.init.prototype.change = function () {
/// <summary>
/// 1: Change function of scroll bar content
/// 1.1 - change() - This function represents the data that refreshes this scrollbar object. In some cases, the data of the content is constantly changing. You can call this function to refresh the data to the current scrollbar object.
/// </summary>
/// <returns type="linkFlyScroll" />
/*
* The properties contained in linkFlyScroll are mainly initialized or redefined in this function:
* isDrag: Is the scrollbar being dragged
* startTop: (Working) Scroll bar start scrolling position
* endTop: (Working) scroll bar end scroll position
* topLimit: Top Limit position of scroll bar
* bottomLimit: the limit position at the bottom of the scroll bar
* context:Content Dom
* scrollRadix: scrolling cardinality
* target:Container Dom
*/
//Reset or read a series of data
var currScroll = this;
currScroll.isDrag = false,
currScroll.startTop = 0,
currScroll.endTop = (currScroll.scrollUl.style.top? parseInt(currScroll.scrollUl.style.top) : 0),
currScroll.topLimit = currScroll.target.scrollTop,
currScroll.bottomLimit = currScroll.target.clientHeight,
currScroll.scrollRadix = 10;
//Get the height of the scroll bar: content height* (container height/content height = container as a percentage of content)
var scrollPx = currScroll.target.clientHeight * (currScroll.target.clientHeight / currScroll.context.offsetHeight);
//Scroll bar height
currScroll.scrollUl.childNodes[1].style.height = scrollPx + 'px';
if (currScroll.context.clientHeight <= currScroll.target.clientHeight && currScroll.options.auto) {
currScroll.scrollUl.style.display = 'none';
} else {
currScroll.scrollUl.style.display = 'block';
//When the scroll bar is displayed, correct the maximum position data
currScroll.bottomLimit -= currScroll.scrollUl.offsetHeight;
}
//Set the scrolling cardinality of the scroll bar (the scroll bar does not scroll 1px content scrolling pixel): (Content height - container height [because the current container has been displayed for one screen])/Scroll bar top (the scroll bar is blank and can be scrolled)
currScroll.scrollRadix = (currScroll.context.offsetHeight - currScroll.target.clientHeight) / currScroll.bottomLimit;
return currScroll;
};
linkFlyScroll.prototype.init.prototype.roll = function (value) {
/// <summary>
/// 1: Scrollbar offset method
/// 1.1 - roll(value) - scroll bar scrolling method
/// </summary>
/// <param name="value" type="Int">
/// Percentage of scrolling targets
/// </param>
/// <returns type="linkFlyScroll" />
var currScroll = this;
if (typeof (value) !== 'number') {
return currScroll;
}
var currTop = (currScroll.bottomLimit - currScroll.topLimit) * value / 100;
currScroll.scrollEvent(currTop);
currScroll.endTop = currTop;
return currScroll;
};
/*
* Tools
*/
var tool = {
setClass: function (element, className) {
/// <summary>
/// 1: Set the class attribute of the element node
/// 1.1 - setClass(element,className) - Set the class attribute of the element node. If there is no such node, create the node and return the modified node object
/// </summary>
/// <param name="element" type="Element Or String">
/// Create the node by passing in String, otherwise modify the node
/// </param>
/// <param name="className" type="String">
/// Class Name
/// </param>
/// <returns type="Element" />
if (typeof element === 'string') {
element = document.createElement(element);
}
element.className = className;
return element;
},
hasClass: function (element, className) {
/// <summary>
/// 1: Determine whether the element has a class
/// 1.1 - hasClass(element,className) - determines whether the element has a class, exceptions in the business (basically no such situation occurs) and the class has a true, otherwise it returns false
/// </summary>
/// <param name="element" type="Element Or String">
/// Node object
/// </param>
/// <param name="className" type="String">
/// Class Name
/// </param>
/// <returns type="Element" />
if (!element || element.nodeType !== 1)//Let the exception pass, and no processing is performed outside
return true;
var elementClassName = element.className;
if (elementClassName.length < 1) {
return false;
}
if (elementClassName == className || elementClassName.match(new RegExp("(^|//s)" + className + "(//s|$)"))) {
return true;
}
return false;
},
addClass: function (element, className) {
/// <summary>
/// 1: [Add] class for element
/// 1.1 - addClass(element,className) - Append to the element and return the modified class
/// </summary>
/// <param name="element" type="Element Or String">
/// Node object
/// </param>
/// <param name="className" type="String">
/// Class Name
/// </param>
/// <returns type="Element" />
if (!tool.hasClass(element, className)) {
if (element.className.length < 1) {
element.className = className;
} else {
element.className += ' ' + className;
}
}
return element;
},
removeClass: function (element, className) {
/// <summary>
/// 1: Remove class for element
/// 1.1 - addClass(element,className) - Remove class for element and return the modified class
/// </summary>
/// <param name="element" type="Element Or String">
/// Node object
/// </param>
/// <param name="className" type="String">
/// Class Name
/// </param>
/// <returns type="Element" />
if (tool.hasClass(element, className)) {
var reg = new RegExp("(^|//s)" + className + "(//s|$)");
element.className = element.className.replace(reg, '');
}
return element;
},
css: function (element, key) {
/// <summary>
/// 1: Get the attribute value specified by element css
/// 1.1 - css(element,className) - Get the attribute value specified by element css
/// </summary>
/// <param name="element" type="Element Or String">
/// Node object
/// </param>
/// <param name="key" type="String">
/// The css attribute to obtain
/// </param>
/// <returns type="String" />
return element.currentStyle ? element.currentStyle[key] : document.defaultView.getComputedStyle(element, false)[key];
},
addEvent: function (element, type, fn) {
/// <summary>
/// 1: Append events to elements
/// 1.1 - css(element, type, fn) - Append events to the element, this point to the event source in the function
/// </summary>
/// <param name="element" type="Element Or String">
/// Node object
/// </param>
/// <param name="type" type="String">
/// Append event name, without characters on
/// </param>
/// <param name="fn" type="Function">
/// Event object
/// </param>
/// <returns type="void" />
if (element.attachEvent) {
element['e' + type + fn] = fn;
element[type + fn] = function () { element['e' + type + fn](window.event); }
element.attachEvent('on' + type, element[type + fn]);
} else if (element.addEventListener) {
element.addEventListener(type, fn, false);
}
},
// removeEvent: function (element, type, fn) {
// /// <summary>
// /// 1: Delete events for elements, this function has not been used
// /// 1.1 - removeEvent(element, type, fn) - Remove event for element
// /// </summary>
// /// <param name="element" type="Element Or String">
// /// Node object
// /// </param>
// /// <param name="type" type="String">
// /// Deleted event name
// /// </param>
// /// <param name="key" type="String">
// /// function name of deleted event
// /// </param>
// /// <returns type="void" />
// if (element.detachEvent) {
// element.detachEvent('on' + type, element[type + fn]);
// element[type + fn] = null;
// } else if (element.removeEventListener) {
// element.removeEventListener(type, fn, false);
// }
// },
addScrollEvent: function (element, fn) {
/// <summary>
/// 1: Append ScrollEvent event
/// 1.1 - addScrollEvent(element,fn) - Append ScrollEvent event to element (special event, mouse wheel scroll event on element)
/// </summary>
/// <param name="element" type="Element Or String">
/// Element node
/// </param>
/// <param name="fn" type="Function">
/// Event method
/// </param>
/// <returns type="void" />
var bindScrollFn = function (e) {
e = e || window.event;
//Judge the scrolling direction of the scroll wheel: Firefox is different from other browsers
e.wheel = (e.wheelDelta ? e.wheelDelta : -e.detail) > 0 ? 1 : -1; //Judge the mouse wheel inverted by the event, 1 is upward, and -1 is downward
//Block the default behavior of the browser
if (e.preventDefault) { //ff
e.preventDefault();
} else {
e.returnValue = false; //ie
}
fn.call(element, e);
}
if (document.addEventListener) {
//ff
element.addEventListener('DOMMouseScroll', bindScrollFn, false);
//w3c
element.addEventListener('mousewheel', bindScrollFn, false);
} else//ie
{
element.attachEvent('onmousewheel', bindScrollFn);
}
},
getEvent: function () {
/// <summary>
/// 1: Get Event object
/// 1.1 - getEvent() - Get Event object without parameters, while compatibilities handle IE and FF
/// </summary>
/// <returns type="Event" />
if (document.all) {
return window.event;
}
func = getEvent.caller;
while (func != null) {
var arg0 = func.arguments[0];
if (arg0) {
if ((arg0.constructor == Event || arg0.constructor == MouseEvent) || (typeof (arg0) == "object" && arg0.preventDefault && arg0.stopPropagation)) {
return arg0;
}
}
func = func.caller;
}
return null;
},
getMousePos: function (ev) {
/// <summary>
/// 1: Get the current mouse coordinates
/// 1.1 - getMousePos(ev) - Get the current mouse coordinates, compatibility processing, and the returned object format: { x: mouse x coordinates, y: mouse y coordinates}
/// </summary>
/// <param name="ev" type="Event">
/// Event event object
/// </param>
/// <returns type="Json" />
if (!ev) {
ev = currScroll.getEvent();
}
if (ev.pageX || ev.pageY) {
return {
x: ev.pageX,
y: ev.pageY
};
}
if (document.documentElement && document.documentElement.scrollTop) {
return {
x: ev.clientX + document.documentElement.scrollLeft - document.documentElement.clientLeft,
y: ev.clientY + document.documentElement.scrollTop - document.documentElement.clientTop
};
}
else if (document.body) {
return {
x: ev.clientX + document.body.scrollLeft - document.body.clientLeft,
y: ev.clientY + document.body.scrollTop - document.body.clientTop
};
}
},
extend: function (oldObj, newObj) {
/// <summary>
/// 1: Merge two objects
/// 1.1 - extend(oldObj,newObj) - Merge two objects and return the merged object, implementing it in clone, so it will not have any impact on the two objects
/// </summary>
/// <param name="oldObj" type="Object">
/// Object A to be merged, which is used as the base object, overwrites the attribute of the same name of the new object into the base object
/// </param>
/// <param name="newObj" type="Object">
/// Object B to be merged
/// </param>
/// <returns type="Object" />
var tempObj = tool.clone(oldObj);
for (var key in newObj) {
if (newObj.hasOwnProperty(key) && !tempObj.hasOwnProperty(key)) {
tempObj[key] = newObj[key];
}
}
return tempObj;
},
clone: function (obj) {
/// <summary>
/// 1: Cloning an object
/// 1.1 - clone(obj) - Clone an object and return the cloned new object. The prototype of the object is the cloned object
/// </summary>
/// <param name="obj" type="Object">
/// The object to clone
/// </param>
/// <returns type="Object" />
function Clone() { }
Clone.prototype = obj;
var newObj = new Clone();
for (var key in newObj) {
if (typeof newObj[key] == "object") {
newObj[key] = tool.clone(newObj[key]);
}
}
return newObj;
},
convertValue: function (value) {
/// <summary>
/// 1: Convert the value to a valid value
/// 1.1 - convertValue(value) - Convert the css value configured by Json to a valid value, please make sure that the value of the value is not "auto"
/// </summary>
/// <param name="value" type="Object">
/// The value to be converted
/// </param>
/// <returns type="Object" />
var reg = /^/d+$/g;
if (typeof (value) === 'number' || reg.test(value)) {
return value + 'px';
} else
return value;
}
};
//Register to window
window.linkFlyScroll = linkFlyScroll;
//Register in the window.so namespace
if (!window.so) {
window.so = {};
}
window.so.scroll = window.linkFlyScroll;
})(window);
Code Example
The code copy is as follows:
<!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>
<title></title>
<link href="linkFlyScroll/linkFlyRollCss.css" rel="stylesheet" type="text/css" />
<script src="linkFlyScroll/linkFlyScroll-1.0.0.js" type="text/javascript"></script>
<script type="text/javascript">
window.onload = function () {
var config = {
auto: true, //When the content does not reach the height of the container, will the scrollbar be automatically hidden
height: '100', //The working height of the scroll bar object (the scroll bar will be displayed if it exceeds this height), auto gets the current height of the object
width: 'auto'//Scrollbar object working width
};
var scrollObj = so.scroll('obj', config);
// scrollObj.change();// When the scrollbar content changes, the scrollbar display needs to be refreshed, then this method is called
// scrollObj.roll(value);// Position the scrollbar to a certain point, the value is the percentage relative to the scrollbar object
};
</script>
</head>
<body>
<div id="obj">
<div>
At present, a new "fashion style" is emerging in the field of corporate management, and some giant companies are "slimming down" for themselves and transforming into smarter and more agile businesses. It is understood that Oracle Software is increasingly shifting its customers' main maintenance costs to consultants and third-party suppliers.
"In China, 90% of Oracle's business is carried out through these partners. In addition, to further ensure Oracle's revenue, CEO Ellison also purchased a small island in Hawaii," said Craig Guarente.
As the global vice president, Guarente is very aware of Oracle's strategies. Guarente has 16 years of work experience and has rich experience in contract management, software license management, and software audit. After leaving Oracle in 2011, he joined Palisade, whose main business is to help Oracle customers provide software contracting, audit intervention and license "optimization".
Guarente said Palisade's business is developing very rapidly. As a third-party organization, Palisade helps customers win large orders because they are closer to the market and can understand user needs more accurately.
Generally speaking, consulting companies help customers sort out their actual needs and what value the software itself can provide. Guarente gave a detailed explanation through practical operations. For example, "If you want to build a new data center, launch a new disaster recovery plan, or if you want to enter the cloud, a third-party company will first develop a planning map and finally implement it to achieve the user's ultimate goal. If the software is deployed in different locations on many servers, the enterprise will lose software. Because enterprise software rarely gets a license key. But Oracle has become a habit and every possible feature can be downloaded in the software environment. Oracle database administrators can diagnose database problems through automatic load repository (AWR) reports. This is a common thing, but you need to have a license for an Oracle database package."
In recent years, with the rise of the software audit wave, many companies are installing software asset management tools to determine what software they use, how long it can last, and how many people in a company are using it. But senior management analyst Hegedus said: "No tool can accurately understand enterprise rules, especially Oracle's product applications, and professional third-party organizations are needed to help users understand software rules."
So how can I patch Oracle's software applications? Oracle President Mark Hurd said last week that at the beginning of enterprise applications, third-party institutions should be defined as service supporters, so that companies can obtain free patch repairs and other support in the future, rather than just purchasing product intellectual property rights. In addition, enterprises should effectively utilize consultants to support the first step in cost control when understanding what software the enterprise uses and what the agreement should include. Don’t blindly leave the software supplier and purchase software according to the process of your predictions and guesses.
</div>
</div>
</body>
</html>
The above is the entire content of this article, and the explanation is very detailed. I hope you like it.