The prototype
- Practical application of the prototype
- How does the prototype achieve its extensibility
Practical application of the prototype
Simple use of jquery and Zepto
<p>jquery test1</p>
<p>jquery test2</p>
<p>jquery test3</p>
<div id="div1">
<p>jquery test in div</p>
</div>
Copy the code
var $p = $("p")
$p.css('font-size'.'40px'// CSS is the prototype method console.log($p.html()) // HTML is the prototype method var$div1 = $("#div1")
$div1.css('color'.'blue'// CSS is the prototype method console.log($div1.html()) // HTML is the prototype methodCopy the code
How does Zepto use prototypes
// Empty object var zepto = {} zepto.init =function(){// in the source code, the processing situation here is more complicated. But because it is the only in view of the prototype, so this will weaken the var slice = Array. The prototype. The dom = slice slice var. Call (document. QuerySelectorAll (selector))returnZepto. Z(dom,selector)} $var $=function(selector){
return zepto.init(selector)
}
Copy the code
// This is the constructorfunction Z(dom, selector) {
var i, len = dom ? dom.length : 0
for (i = 0; i < len; i++) {
this[i] = dom[i]
}
this.length = len
this.selector = selector || ' '
}
zepto.Z = function(dom, selector) {
return new Z(dom, selector)
}
Copy the code
$.fn = {
constructor:zepto.Z,
css:function(key,value){},
html:function(value){}
}
zepto.Z.prototype = Z.prototype = $.fn
Copy the code
Simple Zepto implementation
MyZepto. Js
(function(window) {
var zepto = {};
function Z(dom, selector) {
var i, len = dom ? dom.length : 0;
for (i = 0; i < len; i++) {
this[i] = dom[i];
}
this.length = len;
this.selector = selector || ' ';
}
zepto.Z = function(dom, selector) {
return new Z(dom, selector);
}
zepto.init = function(selector) {
var slice = Array.prototype.slice;
var dom = slice.call(document.querySelectorAll(selector));
return zepto.Z(dom, selector);
}
var $ = function(selector) {
return zepto.init(selector);
}
window.$ = $;
$.fn = {
css: function(key, value) {
console.log(key, value);
},
html: function() {
return "html";
}
}
Z.prototype = $.fn
})(window)
Copy the code
How does jquery use prototypes
var jQuery = function(selector){// Notice the new keyword, the constructor is found in the first stepreturnnew jQuery.fn.init(selector); } // Define the constructor var init = jquery.fn.init =function(selector){ var slice = Array.prototype.slice; var dom = slice.call(document.querySelectorAll(selector)); var i,len=dom? dom.length:0;for(i = 0; i<len; i++) this[i] = dom[i]; this.length = len; this.selector = selector ||' '; } // constructor = {constructor: jQuery, CSS:function(key, value) {},
html: function(value) {}} // Define prototype init.prototype = jquery.fnCopy the code
Extensibility of prototypes
How to demonstrate the extensibility of a prototype
- conclusion
zepto
andjquery
Use of prototypes - Plug-in mechanism
Why put the prototype on $.fn
init.prototype = jQuery.fn;
zepto.Z.prototype = Z.prototype = $.fn
Because you want to extend plug-ins
// make a simple plugin $.fn.getNodeName =function() {return this[0].nodeName
}
Copy the code
benefits
- only
$
Will be exposed to thewindow
On global variables - Unify plug-in extensions to
$.fn.xxx
This interface is easy to use
asynchronous
What is single threading and what does asynchrony have to do with it
- Single thread: Only one thread can do one thing at a time. Two JS segments cannot be executed at the same time
- Reason: Avoid DOM rendering conflicts
- Solution: Asynchronous
Why js has only one thread: avoid DOM rendering collisions
- The browser needs to render the DOM
- JS can modify the DOM structure
- Browser DOM rendering pauses while JS executes
- JS cannot be executed at the same time.
- Webworkers support multithreading, but do not have DOM access
What is the event – loop
- Event polling, JS to achieve asynchronous specific solutions
- Synchronous code, direct execution (main thread)
- Asynchronous functions are first placed in asynchronous queues (task queues)
- After the synchronization function is completed, polling the functions that execute the asynchronous queue
setTimeout(function(){ console.log(1); }, 100); // After 100ms, the asynchronous queue is emptysetTimeout(function(){ console.log(2); }) console.log(3) // After 3, there are only 2 tasks in the asynchronous queue, so there are no tasks in the asynchronous queue, so we poll the asynchronous queue until 1 is put into the asynchronous queue after 100ms. Execute 1 on the main threadCopy the code
$.ajax({
url:'./data.json',
success:function(){// If the network request is successful, success will be placed in the asynchronous queue console.log().'a'); }})setTimeout(function(){
console.log('b')
},100)
setTimeout(function(){
console.log('c');
})
console.log('d') / / print results: / / / / / / c/d/c d/a/a / / / / / / a/b/b won't appear dacb real environmentCopy the code
Solution problems
- Problem 1: not in accordance with the written execution, poor readability
- Problem two: Callback is not easily modularized
Has jQuery Deferred been used
- The change of jQuery1.5
- Using jQuery Deferred
- Introduce the Promise concept initially
JQuery1.5 before
var ajax = $.ajax({
url:'./data.json',
success:function(){
console.log('success1');
console.log('success2');
console.log('success3');
},
error:function(){
console.log('error'); } }) console.log(ajax); // Return an XHR objectCopy the code
After jQuery1.5
The first way:
var ajax = $.ajax('./data.json');
ajax.done(function(){
console.log('success1')
})
.fai(function(){
console.log('fail')
})
.done(function(){
console.log('success2'); }) console.log(ajax); / / deferred objectCopy the code
The second way is:
var ajax = $.ajax('./data.json');
ajax.then(function(){
console.log('success1')},function(){
console.log('error1');
})
.then(function(){
console.log('success2');
},function(){
console.log('error');
})
Copy the code
- You can’t change the asynchronous and single threaded nature of JS
- Callback can only be written to eliminate the form
- It is a syntactic sugar, but decouples the code
- Good withdrawal: Open closed principle (open for extensions, closed for modifications)
Using jQuery Deferred
Give a very simple code, using the setTimeout function
var wait = function(){
var task = function(){
console.log('Execution completed');
}
setTimeout(task,2000)
}
wait(a);Copy the code
New requirement: There may be a lot of code in several steps to perform some particularly complex operations after execution
function waitHandle(){ var dtd = $.Deferred(); // Create a deferred object varwait = function(DTD){// Requires passing in a Deferred object var task =function(){
console.log("Execution completed"); dtd.resolve(); // Dtd.reject () // Async task failure or error};setTimeout(task,2000);
returndtd; } // Notice that there is already a return valuereturn wait(dtd); } // use var w = waithandle().function(){
console.log('ok1');
},function(){
console.log('err2');
})
.then(function(){
console.log('ok2');
},function(){
console.log('err2'); }) // There is also W.wait W.AilCopy the code
Summary: DTD apis fall into two categories, with different intentions
- The first category:
dtd.resolve
、dtd.reject
- The second category:
dtd.then
,dtd.done
,dtd.fail
- These two categories should be separated, otherwise the consequences are serious! It can be executed last in the code above
dtd.reject()
Try the consequences
Use a DTD. Promise ()
function waitHandle(){
var dtd = $.Deferred();
var wait = function(){
var task = function(){
console.log('Execution completed');
dtd.resolve();
}
setTimeout(task,2000)
returndtd.promise(); // Note that we return a promise instead of a deferred object}return wait(dtd)
}
var w = waitHandle(); / / promise object $. When (w). Then (function(){
console.log('ok1');
},function(){
console.log('err1');
})
//w.reject() //w.reject is not a function
Copy the code
Listener invocation: Passively listens and does not interfere with the success or failure of a promise
- You can give an example of the changes to ajax in jQuery1.5
- Explains how to easily encapsulate and use deferred
- Illustrate the difference between Promise and Defrred
To understand it, you need to know its past lives
Basic use and principles of Promise
The basic grammar
fucntion loadImg() {
var promise = new Promise(function(resolve,reject) {
var img = document.getElementById("img")
img.onload = function(){
resolve(img)
}
img.onerror = function(){
reject()
}
})
return promise
}
var src = ""
var result = loadImg(src)
result.then(function() {
console.log(1, img.width)
return img
}, fucntion() {
console.log('error 1')
}).then(function(img) {
console.log(1, img.width)
})
Copy the code
Exception handling
provisions
then
Accept only one function (only one successful callback) and use it allcatch
Catch exceptions
There are two anomalies:
- Program logic exception
- Within the business,
reject()
, etc.
The process passes information out in reject(‘ image path error ‘), which can be caught by ‘.catch()’
var src = ""
var result = loadImg(src)
result.then(function() {
console.log(1, img.width)
return img
}).then(function(img) {
console.log(1, img.width)
}).catch(function(ex) {console.log(ex)})Copy the code
Several series
var scr1 = 'https://www.imooc.com/static/img/index/logo_new.png';
var result1 = loadImg(src1);
var src2 = 'https://www.imooc.com/static/img/index/logo_new1.png';
var result2 = loadImg(src2);
result1.then(function(img1) {
console.log('First image load completed', img1.width);
returnresult2; / / important}). Then (function(img2) {
console.log('Second image load completed', img2.width);
}).catch(function(ex) {
console.log(ex);
})
Copy the code
Promise. All and Promise. Race
Promise.all
To receive apromise
Array of objects- After all operations are complete, execute them in a unified manner
success
Promise.all([result1, result2]).then(datas => {console.log(datas[0]); console.log(datas[0]); console.log(datas[1]); })Copy the code
Promise.race
Receive one containing multiplepromise
Array of objects
- As long as one is done, execute
success
Promise.race([result1, result2]). Then (data => {//data that is the return value of the first completed Promise console.log(data); })Copy the code
Promise standard
- state
- Three states:
pending
.fulfilled
.rejected
- Initial state:
pending
pending
intofulfilled
Or,pending
intorejected
- The change in state is irreversible
- Initial state:
- then
promise
Must be implementedthen
This methodthen()
Two functions must be accepted as standardsthen
The return must be onepromise
The instance
No return is result returned by default
Promise to summarize
- The basic grammar
- How to catch exceptions (
Error
andreject
) - Benefits of multiple series-chain executions
Promise.all
andPromise.race
Promise
Standard – State change,then
function
Introduce async/await(difference and connection with Promise)
In THE ES7 proposal, it is used a lot and Babel has supported it
Koa framework async/await replaces generator
The solution is asynchronous execution and writing logic
Then simply splits the callback
var w = watiHandle()
w.then(function() {... },function() {... }) .then(function() {... },function() {... })Copy the code
Async /await is the most direct way to write async/await
const load = async function(){
const result1 = await loadImg(src1)
console.log(result1)
const result2 = await loadImg(src2)
console.log(result2)
}
load()
Copy the code
usage
- use
await
Must be used after the functionasync
logoawait
Followed by onePromise
The instance- Need to be
balbel-polyfill
(compatible)
The characteristics of
- Using the
Promise
There is no andPromise
conflict - It is written completely synchronously, with no callback function
- But: can’t change
JS
Single-threaded, asynchronous nature
Summarize the current asynchronous JS scheme
- jQuery Defered
- promise
- async/await
- Generator (to solve asynchrony is not to solve asynchrony)
Virtual DOM
What is vDOM? Why does vDOM exist?
What is the vdom
- Virtual DOM
- Simulate the DOM structure with JS
- The comparison of DOM changes is done in the JS layer (Turing-complete language: language that can implement various logic).
- Improved redraw performance
DOM
<ul id="list">
<li class="item">Item 1</li>
<li class="item">Item 2</li>
</ul>
Copy the code
Virtual DOM
{
tag: 'ul',
attrs: {
id: 'list'
},
children: [{
tag: 'li',
attrs: { className: 'item' },
children: ['item1']
},
{
tag: 'li',
attrs: { className: 'item' },
children: ['item2']}]} //className replaces class because class is a reserved js wordCopy the code
The biggest performance drain on browsers is DOM manipulation, DOM manipulation is very expensive and now browsers execute JS very fast and that’s why vDOM exists
A requirements scenario
// Modify any information, and the table will be modified as well [{name:'zhangsan',
age: 20,
address: 'beijing'
},
{
name: 'lisi',
age: 21,
address: 'shanghai'
},
{
name: 'wangwu',
age: 22,
address: 'guangzhou'}]Copy the code
with
jQery
implementation
Funciton render(data) {// this function is funciton render(data) {'#btn-change').click(function(){
data[1].age = 30;
data[2].address = 'shenzhen'; render(data); }) // Render (data)Copy the code
//render functionfunction render(data) {
$container = $("#container"); // Empty the existing content$container.html(' '); // Splice table var$table = $('<table>')
$table.append($('<tr><td>name</td><td>age</td><td>address</td></tr>'))
data.forEach(item => {
$table.append($('<tr><td>' + item.name + '</td><td>' + item.age + '</td><td>' + item.address + '</td></tr>'))
$container.append($table)}); } // Only render once, relatively efficient //DOM rendering is the most expensive and can only be avoidedCopy the code
Problems encountered
- DOM manipulation is “expensive” and JS runs efficiently
- Minimize DOM manipulation, not “clean up “(clear reset)
- The more complex the project, the more severe the impact
- Vdom solves this problem
var div = document.createElement('div');
var item,result = ' ';
for(item in div){
result += '|'+ item; } console.log(result); // The default DOM node created by the browser, Attributes are a lot of //result |align|title|lang|translate|dir|dataset|hidden|tabIndex|accessKey|draggable|spellcheck|autocapitalize|contentEditable|is ContentEditable|inputMode|offsetParent|offsetTop|offsetLeft|offsetWidth|offsetHeight|style|innerText|outerText|onabort|o nblur|oncancel|oncanplay|oncanplaythrough|onchange|onclick|onclose|oncontextmenu|oncuechange|ondblclick|ondrag|ondragend |ondragenter|ondragleave|ondragover|ondragstart|ondrop|ondurationchange|onemptied|onended|onerror|onfocus|oninput|oninva lid|onkeydown|onkeypress|onkeyup|onload|onloadeddata|onloadedmetadata|onloadstart|onmousedown|onmouseenter|onmouseleave| onmousemove|onmouseout|onmouseover|onmouseup|onmousewheel|onpause|onplay|onplaying|onprogress|onratechange|onreset|onres ize|onscroll|onseeked|onseeking|onselect|onstalled|onsubmit|onsuspend|ontimeupdate|ontoggle|onvolumechange|onwaiting|onw heel|onauxclick|ongotpointercapture|onlostpointercapture|onpointerdown|onpointermove|onpointerup|onpointercancel|onpoint erover|onpointerout|onpointerenter|onpointerleave|nonce|click|focus|blur|namespaceURI|prefix|localName|tagName|id|className|classList|slot|attributes|shadowRoot|assignedSlot|innerHTML|outerHTML|scrollTop|scrollLeft|scr ollWidth|scrollHeight|clientTop|clientLeft|clientWidth|clientHeight|attributeStyleMap|onbeforecopy|onbeforecut|onbeforep aste|oncopy|oncut|onpaste|onsearch|onselectstart|previousElementSibling|nextElementSibling|children|firstElementChild|la stElementChild|childElementCount|onwebkitfullscreenchange|onwebkitfullscreenerror|setPointerCapture|releasePointerCapture|hasPointerCapture|hasAttributes|getAttributeNames|getAttribute|getAttributeNS|setAttribute|setAttributeNS|removeAttribute|removeAttributeNS|hasAttribute|hasAttributeNS|toggleAttribute|getAttributeNode|getAttributeN odeNS|setAttributeNode|setAttributeNodeNS|removeAttributeNode|closest|matches|webkitMatchesSelector|attachShadow|getElementsByTagName|getElementsB yTagNameNS|getElementsByClassName|insertAdjacentElement|insertAdjacentText|insertAdjacentHTML|requestPointerLock|getClie ntRects|getBoundingClientRect|scrollIntoView|scrollIntoViewIfNeeded|animate|computedStyleMap|before|after|replaceWith|re move|prepend|append|querySelector|querySelectorAll|webkitRequestFullScreen|webkitRequestFullscreen|scroll|scrollTo|scrol lBy|createShadowRoot|getDestinationInsertionPoints|ELEMENT_NODE|ATTRIBUTE_NODE|TEXT_NODE|CDATA_SECTION_NODE|ENTITY_REFER ENCE_NODE|ENTITY_NODE|PROCESSING_INSTRUCTION_NODE|COMMENT_NODE|DOCUMENT_NODE|DOCUMENT_TYPE_NODE|DOCUMENT_FRAGMENT_NODE|N OTATION_NODE|DOCUMENT_POSITION_DISCONNECTED|DOCUMENT_POSITION_PRECEDING|DOCUMENT_POSITION_FOLLOWING|DOCUMENT_POSITION_CO NTAINS|DOCUMENT_POSITION_CONTAINED_BY|DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC|nodeType|nodeName|baseURI|isConnected|ow nerDocument|parentNode|parentElement|childNodes|firstChild|lastChild|previousSibling|nextSibling|nodeValue|textContent|h asChildNodes|getRootNode|normalize|cloneNode|isEqualNode|isSameNode|compareDocumentPosition|contains|lookupPrefix|lookupNamespaceURI|isDefaultNamespace|insertBe fore|appendChild|replaceChild|removeChild|addEventListener|removeEventListener|dispatchEventCopy the code
vdom
How to apply, coreAPI
What is the
Introduce snabbdom
A library that implements VDOM, vUE Upgrade 2.0 borrows snabbDOM algorithms
var container = document.getElementById('container')
var vnode = h('div#container.two.classes', { on: { click: someFn } }, [
h('span', { style: { fontWeight: 'bold' }, 'This is bold' }),
'and this is just normal text',
h('a', { props: { href: '/foo'}},'I\'ll take you places') ]) //patch into empty DOM element - this modifies the DOM as a side effect patch(container, vnode) var newVnode = h('div#container.two.classes', { on: { click: anotherEventHandle } }, [
h('span', { style: { fontWeight: 'normal', fontStyle: 'italic'}},'this is now italic type'),
'and this is still just normal text',
h('a', { props: { href: '/bar'}},'I\'ll take you places') ]) //send `patch` invocation patch(vnode, newVnode); //Snabbdom efficiently updates the old view to the new stateCopy the code
H function
{
tar: 'ul',
attrs: {
id: 'list'
},
children: [
{
tag: 'li',
attrs: {
className: 'item',
children: ['item1']
}
},
{
tag: 'li',
attrs: {
className: 'item'
},
children: ['item2']]}}Copy the code
The corresponding vnode
var vnode = h('ul#list', {}, [
h('li.item', {}, 'Item1'),
h('li.item', {}, 'Item')])Copy the code
The patch function
var vnode = h('ul#list', {}, [
h('li.item', {}, 'Item1'),
h('li.item', {}, 'Item2')
])
var container = document.getElementById('container'Var btnChange = document.getelementById ('btn-change')
btnChange.addEventListener('click'.function() {
var newVnode = h('ul#list', {}, [
h('li.item', {}, 'Item 111'),
h('li.item', {}, 'Item 222'),
h('li.item', {}, 'Item 333')
])
patch(vnode, newVnode)
})
Copy the code
<div id="container"></div>
<button id="btn-change">change</button>
<script src="https://cdn.bootcss.com/snabbdom/0.7.2/snabbdom.js"></script>
<script src="https://cdn.bootcss.com/snabbdom/0.7.2/snabbdom-class.js"></script>
<script src="https://cdn.bootcss.com/snabbdom/0.7.2/snabbdom-props.js"></script>
<script src="https://cdn.bootcss.com/snabbdom/0.7.2/snabbdom-style.js"></script>
<script src="https://cdn.bootcss.com/snabbdom/0.7.2/snabbdom-eventlisteners.js"></script>
<script src="https://cdn.bootcss.com/snabbdom/0.7.2/h.js"></script>
Copy the code
<script type="text/javascript"Var patch = snabbdom.init([snabbdom_class, snabbdom_props, snabbdom_style, Var h = snabbdom.h var container = document.getelementById ('container'Var vnode = h('ul#list',{},[
h('li.list', {},'Item1'),
h('li.list', {},'Item2'),
])
patch(container,vnode)
document.getElementById('btn-change').addEventListener('click'.function(){// generate newVode var newVnode = h('ul#list',{},[
h('li.list', {},'Item1'),
h('li.item', {},'Item B'),
h('li.item', {},'Item 3')
])
patch(vnode,newVnode)
})
</script>
Copy the code
Re-implement the previous demo(with
snabbdom
Implementation)
var snabbdom = window.snabbdom
var patch = snabbdom.init([
snabbdom_class,
snabbdom_props,
snabbdom_style,
snabbdom_eventlisteners
])
var h = snabbdom.h
var container = document.getElementById('container')
var btnChange = document.getElementById('btn-change')
var vnode
var data = [{
name: 'zhangsan',
age: 20,
address: 'beijing'
},
{
name: 'zhangsan',
age: 20,
address: 'shanghai'
},
{
name: 'zhangsan',
age: 20,
address: 'shenzhen'
}
]
data.unshift({
name:'Name:',
age:'Age:',
address:'Address:'
})
render(data);
function render(data){
var newVnode = h('table',{},data.map(function(item){
var tds = [],i
for(i in item){
if(item.hasOwnProperty(i)){
tds.push(h('td',{},item[i]+' '))}}return h('tr',{},tds)
}))
if(vnode){
patch(vnode,newVnode)
}elseVnode = {patch (container, newVnode)}} btnChange newVnode / / store the current vnode results. AddEventListener ('click'.function(){
data[1].age = 30
data[2].address = 'shenzhen'
//re-render
render(data)
})
Copy the code
Core API
- Use of h function
h('< tag name >', {... Attribute... },[... child element...] ) h('< tag name >', {... Attribute... },'... ')
Copy the code
- Patch function Usage
patch(container,vnode)
patch(vnode,newVnode) //rerender
Copy the code
Let me introduce the diff algorithm
What is the Diff algorithm
Diff in Linux: Find the difference between two files:
diff log1.txt log2.txt
Copy the code
Git diff: The difference between before and after the change
git diff xxxx.js
Copy the code
Some online differentiation sites on the web
http://tool.oschina.net/diff/
Copy the code
Diff algorithm is not a concept proposed by VDOM. It has always existed and is now applied to VDOM. It compares two virtual DOM
To numerous is Jane
diff
The algorithm is very complex, very difficult to achieve, a large amount of source code- Cut to the chase, explain the core process, and don’t care about details
- Most interviewers don’t know the details, but they care about the core process
- Stripped of the complexity, it is still very challenging
Why does VDOM use diff
DOM
Operations are “expensive”, so keep them to a minimumDOM
operation- Find out the
DOM
Nodes that must be updated are updated, others are not updated - The process of “finding out” requires
diff
algorithm
Diff algorithm to achieve the diFF implementation process
patch(container,vnode)
How do I use VNodes to generate real DOM nodes
{
tag: 'ul',
attrs: {
id: 'list'
},
children: [
{
tag: 'li',
attrs: {
className: 'item'
},
children:['item 1']]}}Copy the code
<ul id = "list">
<li class='item'>Item 1</li>
</ul>
Copy the code
Simple implementation algorithm
function createElement(vnode) {
var tag = vnode.tag;
var attrs = vnode.attrs || {};
var children = vnode.children || [];
if(! tag) {returnVar elem = document.createElement(tag); // attribute var attrName;for (attrName in atts) {
if(attrs.hasOwnProperty(attrName)) { elem.setAttribute(attrName, Attrs [attrName])}} // Children.array.forEach(childVnode => {em.appendChild(createElement(childVnode))});return elem;
}
Copy the code
patch(vnode,newVnode)
{
tag: 'ul',
attrs: { id: 'list' },
children: [{
tag: 'li',
attrs: { className: 'item' },
children: ["Item 1"]
},
{
tag: 'li',
attrs: {
className: 'item',
children: ['Item 2'}}]}Copy the code
Contrast:
{
tag: 'ul',
attrs: { id: 'list' },
children: [{
tag: 'li',
attrs: { className: 'item' },
children: ["Item 1"]
},
{
tag: 'li',
attrs: {
className: 'item',
children: ['Item 222']
}
},
{
tag: 'li',
attrs: {
className: 'item',
children: ['Item 3'}}]}Copy the code
Simple implementation
functionupdateChildren(vnode, newVnode) { var children = vnode.children || []; var newChildren = newVnode.children || []; ForEach ((child, index) => {var newChild = newChildren[index];if (newChild == null) {
return;
}
if (child.tag === newChild.tag) {
updateChildren(child, newChild)
} else {
replaceNode(child, newChild)
}
});
}
Copy the code
- Nodes are added and deleted
- Node reordering
- Node properties, styles, event bindings
- How to actively squeeze performance
MVVM
andVue
usejQuery
And using a framework
Separation and decoupling of data and view (Closed open principle)
jquery
The data and view are mixed together, which does not meet the open and closed principlevue
: Combines data with Vue objectsView
It’s completely separated
Data-driven views
jquery
It goes against the grain,jquery
Modify the view directlyDOM
vue
Operations on data no longer need to reference the correspondingDOM
Object, throughVue
The object of thisvm
Implement binding to each other. A data-driven view that only cares about data changes,DOM
Operation encapsulated
rightMVVM
The understanding of the
MVC
MVVM
Model
: Data, modelView
: Views, templates (views and models are separate)ViewModel
: connectionModel
andView
MVVM is not an innovation, ViewModel is a kind of micro innovation developed from MVC, combined with the innovation of front-end scenarios
How to implement MVVM
Vue
The three elements
- responsive:
vue
How to listen indata
Each property of the - Template engine: How are vue templates parsed and instructions processed
- Apply colours to a drawing:
vue
How does the template render intohtml
And the rendering process
vue
How to achieve reactive in
What is reactive
- Modify the
data
After the property,vue
Listen immediately (and render the page immediately) data
Property is proxied tovm
on
Object.defineProperty
API added in ES5, so Vue does not support older browsers (because older browsers do not support this property)
var obj = {};
var _name = 'zhangsan';
Object.defineProperty(obj,"_name",{
get:function(){
console.log("get");
return _name;
},
set:function(newVal){ console.log(newVal); _name = newVal; }}); Console. log(obj.name) // Can listen to obj.name ='list'
Copy the code
Analog implementation
var vm = new Vue({
el: '#app',
data: {
price: 100,
name: 'zhangsan'}})Copy the code
var vm = {}
var data = {
name: 'zhangsan',
price: 100
}
var key, value
for (key inData) {// Hit closure. Create a new function that guarantees the independent scope of the key (function(key) {
Object.defineProperty(vm, key, {
get: function() {
console.log('get')
return data[key]
},
set: function(newVal) {
console.log('set')
data[key] = newVal
}
})
})(key)
}
Copy the code
vue
How to parse templates
What is a template
- Essence: string; Have logic, as
v-if
.if-else-if
, embeddedJS variable
. - with
html
The format is very similar, but very different (static), and eventually you have to convert tohtml
According to - The template must eventually be converted to
JS
code- 1. Because there is logic (
v-for
.v-if
) must be usedJS
To achieve (Turing complete) - 2, convert to
html
Render the page, must useJS
To achieve - Therefore, it is important to convert the template to one
JS
Function (render
Function)
- 1. Because there is logic (
render
function
Look at the use of with()
function fn1() {
with(obj) {
console.log(name);
console.log(age);
getAddress()
}
}
Copy the code
The simplest example
<div id="app">
<p>{{price}}</p>
</div>
Copy the code
With (this) {//this: vmreturn _c(
'div',
{
attrs: { "id": "app" }
},
[
_c('p'[_v(_s(price))])}Copy the code
ƒ (a, b, c, d) {return createElement(vm, a, b, c, d, false); }
//vm._v
ƒ createTextVNode (val) {
returnNew VNode(undefined, undefined, String(val))}return val == null? ' ': typeof val === 'object'? JSON.stringify(val, null,2): String(val)
}
Copy the code
- All the information in the template is included
render
In the function this
namelyvm
price
namelythis.price
, i.e.,data
In theprice
_c
namelythis._c
namelyvm._c
A more complicated example
<div id="app">
<div>
<input v-model="title">
<button v-on:click="add">submit</button>
</div>
<div>
<ul>
<li v-for="item in list">{{item}}</li>
</ul>
</div>
</div>
Copy the code
How to find the render function: code.render
How the template generates the render function:
Precompilation has been supported since vue2.0. We write templates in the development environment, compile and package them, and generate the render function (JS code) in the production environment.
With (this){// this is vmreturn _c(
'div',
{
attrs:{"id":"app"}
},
[
_c(
'div',
[
_c(
'input',
{
directives:[
{
name:"model",
rawName:"v-model",
value:(title),
expression:"title"
}
],
domProps:{
"value":(title)
},
on:{
"input":function($event) {if($event.target.composing)return;
title=$event.target.value
}
}
}
),
_v(""),
_c(
'button',
{
on:{
"click":add
}
},
[_v("submit")]
)
]
),
_v(""),
_c('div',
[
_c(
'ul',
_l((list),function(item){return _c('li',[_v(_s(item))])})
)
]
)
]
)
}
Copy the code
//vm._l
function renderList(val,render) {
var ret, i, l, keys, key;
if (Array.isArray(val) || typeof val === 'string') {
ret = new Array(val.length);
for(i = 0, l = val.length; i < l; i++) { ret[i] = render(val[i], i); }}else if (typeof val === 'number') {
ret = new Array(val);
for(i = 0; i < val; i++) { ret[i] = render(i + 1, i); }}else if (isObject(val)) {
keys = Object.keys(val);
ret = new Array(keys.length);
for(i = 0, l = keys.length; i < l; i++) { key = keys[i]; ret[i] = render(val[key], key, i); }}if (isDef(ret)) {
(ret)._isVList = true;
}
return ret
}
Copy the code
v-model
How is that done?v-on:click
How is that donev-for
How is that done
Render function and DOM
- The “logic” in the template (
v-for
.v-if
The problem of) - That leaves the problem of template generating HTML
- Also, what is vm_c?
render
What does the function return- Vm._c is essentially equivalent to
snabbdom
In theh
function render
After the function executes, it returnsvnode
- Vm._c is essentially equivalent to
vm._update(vnode) {
const prevVnode = vm._vnode
vm._vnode = vnode
if(! prevVnode) { vm.$sel = vm.__patch__(vm.$sel, vnode) // Same as the patch function in snabbdom}else {
vm.$sel = vm.__patch__(prevVnode, vnode)
}
}
funciton updateComponentVnode vm._update(vm._render())} {//vm._render ()}Copy the code
updateComponent
Implemented in thevdom
thepatch
- The first rendering of the page executes
updateComponent
data
For each attribute modification, runupdataCommponent
vue
Implementation process of
Step 1: Parse the template into the Render function
with
The use of the- All the information in the template is captured
render
Function contains - Used in the template
data
Properties in, all become JS variables - In the template
v-model
,v-if
,v-on
It all becomes JS logic render
The function returnsvnode
Step 2: Responsive listening
Object.defineProperty
- will
data
Property proxy tovm
on
Step 3: Render for the first time, display the page, and bind dependencies
- First render, execute
updateaComponent
, the implementation ofvm._render()
- perform
render
Function, which accesses thevm.list
andvm.title
- It’s going to be reactive
get
Method listens on (why listen on GET? Don’t you just listen to set?data
There are a number of attributes in the. Some will be used and some may not be used- The one that’s being used goes to
get
What’s not used doesn’t goget
- Did not go to
get
Attributes in,set
When we don’t need relationships - Avoid unnecessary repetitive rendering
- perform
updateComponent
, will govdom
thepatch
methods patch
willvnode
To renderDOM
The initial rendering is complete
Step 4: Data property changes, rerender is triggered
- Property modification, to be responsive
set
Listen to the set
Performed in theupdateaComponetn
updateComponent
To performvm._render()
- The generated
vnode
andprevVnode
Through thepatch
To compare - Render to the
html
In the
Componentization and React
- Relationship between JSX and VDOM
- So let’s talk about the setState process
- React and Vue
A little bit about componentization
todolist Demo1
The command line
npm i create-react-app -g
create-react-app react-test
npm start
- app.js
import Todo from './components/todo/index.js';
class App extends Component {
render() {
return (
<div className="App"> <Todo></Todo> </div> ); }}export default App;
Copy the code
- src
= >
components= >
todo
import React, { Component } from 'react'
class Todo extends Component {
constructor(props) {
super(props)
}
render() {
return (
<p> this is todo component </p>
)
}
}
export default Todo
Copy the code
todolist Demo2
list
=>
todo=>
index.js
import React, { Component } from 'react'
class List extends Component{
constructor(props){
super(props)
}
render() {
const list = this.props.data
return (
<ul>
{
list.map((item,index) =>{
return <li key={index}>{item}</li>
})
}
</ul>
)
}
}
export default List
Copy the code
Have to add the key
todo.js
import React, { Component } from 'react'
import List from './list/index.js';
import Input from './input/index.js';
class Todo extends Component {
constructor(props) {
super(props)
this.state = {
list:[]
}
}
render() {
returnBind (this)}/> <List data={this.state. List}/> </div>)}/ / Add the List automatically List this.setState({list:currentList.concat(title)})}}export default Todo
Copy the code
list
=>
input=>
index.js
import React, { Component } from "react";
class Input extends Component {
constructor(props) {
super(props);
this.state = {
title: ""
};
}
render() {
return(
<div>
<input value={this.state.title} onChange={this.changeHandle.bind(this)} />
<button onClick={this.clickHandle.bind(this)}>submit</button>
</div>
)
}
changeHandle(event) {
this.setState({
title: event.target.value
});
}
clickHandle() { const title = this.state.title; // addTitle to the list const addTitle = this.props. AddTitle; addTitle(title); // Empty this.setState({title:""}); }}export default Input
Copy the code
A little bit about componentization
Component encapsulation
- view
- data
- Change logic (data-driven view)
Component reuse
- Props to pass
- reuse
JSX
What is the essence
JSX grammar
html
In the form of- Introduce JS variables and expressions
if... else...
- cycle
style
And the className- The event
JSX parses to JS
- JSX is syntax sugar
- The development environment compiles JSX to JS code
- JSX writing method greatly reduces the learning cost and coding workload
- At the same time,
JSX
Also increasesdebug
The cost of
/*JSX code */ var profile = <div> <img SRC ="avater.png" className="profile"/>
<h3>{[user.firstName,user.lastName].join(' ')} < / h3 > < / div > -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - / / end parsed into var profile = React.createElement("div",null,
React.createElement("img",{src:"avater.png",className:"profile"}),
React.createElement("h3",null,[user.firstName,user.lastName].join("")))
Copy the code
React.createElement Parameter Description
React.createElement('div', {'id':'div1'},child1,child2,child3)
React.createElement('div', {'id':'div1'}, [...]. )Copy the code
vdom
和h()
vue
the_c()
react
thecreateElement
render(){
const list = this.props.data
return{
<ul>
{
list.map((list,index)=>{
return <li key={index}>{item}</li>>
})
}
</ul>
}
}
----------------------------------------------------------------------------
function render(){
const list = this.props.data;
return React.createElement(
'ul'.'null',
list.map((item,index) => {
return React.createElement(
"li", {key:index}, item ); })); }Copy the code
JSX independent standard
JSX
isReact
Introduced, but notReact
The uniqueReact
It has been opened up as a stand-alone standard and is available for other projectsReact.createElement
It’s customizable- Description: its own function is complete; Compatibility with other standards and scalability
Hybrid
- Mobile accounts for the majority of traffic, by far
pc
- First-tier Internet companies have their own
APP
- these
APP
There is a large proportion of front-end code, take wechat for example, you browse wechat content every day, a lot of it is front-end
hybrid
What is it and whyHybrid, how do you do that
hybrid
Text interpretation
hybrid
This is “hybrid”, which is the mixed development of front-end and client- Front-end developers and client personnel need to cooperate to complete
- Some links may also be involved
server
end
Existence value, why use
hybrid
- Fast iteration update [Key] (without APP review)
- Smooth experience (similar to NA experience)
- Reduce development and communication costs, and both ends share a common set of code
webview
- Is a component in an app (apps can have it
webview
Or not) - Used to load h5 pages, a small browser kernel
file:// agreement
- In fact, from the very beginning of HTML development, the file protocol has been used
- Load local files, quick
- Network loading is slow
- Load local files, quick
- The importance of standards
In order to achieve the same experience as the native, the loading speed must be extremely fast, abnormal fast, and almost as fast as the client
hybrid
Applicable scenario
- Using NA: The experience needs to be extreme and changes are not frequent (e.g. the front page of the headlines)
- Using Hybrid: High experience requirements and frequent changes (e.g., headline news details page)
- Use H5: Experience is not required, not commonly used (such as reporting, feedback and other pages)
hybrid
The specific implementation
- The front end does a static page (HTML JS CSS), the file to the client
- The client gets the front-end static page and stores it in the APP as a file
- The client is in a WebView
- Load static pages using the File protocol
How to update the APP in real time after it is released
Analysis of the
- Replace static files on each client
- Only the client can do it (the client is developed by us)
- The client downloads the latest static file from serve
- We maintain static files for the server
The specific implementation
- A version number is available, for example, 201803211015
- Compress the static file into a ZIP package and upload it to the server
- Each time the client starts, it checks the version number on the server
- If the server version is greater than the client version, download the latest ZIP package
- After downloading, unpack the package and overwrite the existing files
hybrid
andh5
The difference between
Advantages:
- Better experience, basically the same as NA experience
- Fast iteration without APP review
Disadvantages:
- Development costs are high. Joint investigation, testing and bug checking are more troublesome
- High operation and maintenance costs. (Refer to the process of updating and going online previously)
Applicable scenarios:
hybrid
: Stable product functions, high experience requirements, frequent iterationh5
: Single operation activities (such as XX red envelope) or not commonly used functionshybrid
Suitable for product type,h5
Operational type
JS communicates with the client
How does the front end get the content
- News details page applies
hybrid
How does the front end get news content - You can’t get it with Ajax. First cross-domain (
ajax
ishttp
Protocol), the second speed is slow. - The client gets the news content, then the JS communication gets the content and renders it.
JS basic form of communication with the client
Schema Protocol introduction and usage
- The HTTP (S) and File protocols were introduced earlier
- Schema protocol – A convention for communication between the front-end and the client
function invokScan() {
window['_invok_scan_callback'] = function(result){
alert(result)
}
var iframe = document.createElement('iframe')
iframe.style.display = 'none'
iframe.src = 'weixin://dl/scan? k1=v1&k1=v2&callback=_invok_scan_callback'Var body = document.body body.appendChild(iframe)setTimeout(() => {
body.removeChild(iframe)
iframe = none
});
}
document.getElementById('btn').addEventListener('click'.function() {
invokScan();
})
Copy the code
The encapsulation used by schema
What we want to achieve after encapsulation:
*/ window.invok.share({title: {title:});'xxxx',content:'xxx'},funciton(result){
if(result.error === 0){
alert('Share the success')}else{// share failure alert(result.message)}})Copy the code
/ / sharefunction invokeShare(data,callback){
_invoke('share',data,callback)} // Log infunction invokeLogin(data,callback){
_invoke('login',data,callback)function invokeScan(data,callback){
_invoke('scan',data,callback)
}
Copy the code
Invoke = {share:invokeShare, login:invokeLogin, scan:invokeScan}Copy the code
function_invoke(action,data,callback){// Invoke schema protocol var schema ='myapp://utils';
scheam += '/' + action;
scheam += '? a=a';
var key;
for(key in data){
if(data.hasOwnProperty(key)){
schema += '&' + key + '=' +data[key]
}
}
}
Copy the code
// Handle callback var callbackName =' '
if(typeof callback == 'string'){
callbackName = callback
}else{
callbackName = action + Date.now()
window[callbackName] = callback
}
schema += '&callback' + callbackName
Copy the code
(function(window, undefined) {// Call schema encapsulationfunction_invoke(action, data, callback) {var schema ='myapp://utils/'+ action; // Schema +='? a=a';
var key;
for (key in data) {
if (data.hasOwnProperty(key)) {
schema += '&' + key + '='+ data[key]; }} // handle callback var callbackName =' ';
if (typeof callback === 'string') {
callbackName = callback
} else {
callbackName = action + Date.now()
window[callbackName] = callback
}
schema += 'allback = callbackName'} // expose the global variable window.invoke = {share:function(data, callback) {
_invoke('share', data, callback)
},
scan: function(data, callback) {
_invoke('scan', data, callback)
},
login: function(data, callback) {
_invoke('login', data, callback)
}
}
})(window)
Copy the code
Built-in online
- Package the code encapsulated above, called
invoke.js
, built into the client - The client starts each time
webview
, are executed by defaultinvoke.js
- Local load, no network request, no hacker can see
schema
Protocol, more secure
conclusion
- The basic form of communication: invoking capabilities, passing parameters, listening for callbacks
- Understanding and using the Schema protocol
- Call the encapsulation of schema code
- Built-in online: faster and safer