Ancient times of the Internet
Now
Java Script was born
September 1995
jQuery released
August 2006
AngularJS
October 2010
React
May 2013
ES6
June 2015
Ancient times of the Internet
Now
Java Script was born
September 1995
jQuery released
August 2006
AngularJS
October 2010
React
May 2013
IE 6 lost support
January 2016
Ancient times of the Internet
Now
Java Script was born
September 1995
jQuery released
August 2006
AngularJS
October 2010
React
May 2013
IE 6 lost support
January 2016
IE 11 lost support
October 2025
let childOb = !shallow && observe(val)
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter () {
const value = getter ? getter.call(obj) : val
if (Dep.target) {
dep.depend()
if (childOb) {
childOb.dep.depend()
if (Array.isArray(value)) {
dependArray(value)
}
}
}
return value
},
set: function reactiveSetter (newVal) {
const value = getter ? getter.call(obj) : val
if (newVal === value || (newVal !== newVal && value !== value)) {
return
}
if (process.env.NODE_ENV !== 'production' && customSetter) {
customSetter()
}
if (getter && !setter) return
if (setter) {
setter.call(obj, newVal)
} else {
val = newVal
}
childOb = !shallow && observe(newVal)
dep.notify()
}
})
With Proxy API
LESS IS BETTER
data = new Proxy(data_without_proxy, { // Override data to have a proxy in the middle
get(obj, key) {
deps.get(key).depend(); // <-- Remember the target we're running
return obj[key]; // call original data
},
set(obj, key, newVal) {
obj[key] = newVal; // Set original data to new value
deps.get(key).notify(); // <-- Re-run stored functions
return true;
}
});
Evan You on Proxies
2.5
3.x
Rendering of 3000 state-full components
Half the memory usage
Half the rendering time
Twice the user happiness
import { mapGetters } from 'vuex';
export default {
// ...
computed: {
...mapGetters([
'doneTodosCount',
'anotherGetter'
// ...
])
}
};
/**
* Reduce the code which written in Vue.js for getting the getters
* @param {String} [namespace] - Module's namespace
* @param {Object|Array} getters
* @return {Object}
*/
export const mapGetters = normalizeNamespace((namespace, getters) => {
const res = {}
normalizeMap(getters).forEach(({ key, val }) => {
// The namespace has been mutated by normalizeNamespace
val = namespace + val
res[key] = function mappedGetter () {
if (namespace && !getModuleByNamespace(this.$store, 'mapGetters', namespace)) {
return
}
if (process.env.NODE_ENV !== 'production' && !(val in this.$store.getters)) {
console.error(`[vuex] unknown getter: ${val}`)
return
}
return this.$store.getters[val]
}
// mark vuex getter for devtools
res[key].vuex = true
})
return res
})
Vue.js—Difference between v-model and v-bind
Question:
Numbers:
Documentation:
<input v-model="searchText">
<input
v-bind:value="searchText"
v-on:input="searchText = $event.target.value"
>
Remember that:
does the same thing as:
Action
State
View
Component
Mutation
state
Getter
User
Auth
Conversations
Notifications
Middleware
// define a mixin object
var myMixin = {
created: function () {
this.hello()
},
methods: {
hello: function () {
console.log('hello from mixin!')
}
}
}
// define a component that uses this mixin
var Component = Vue.extend({
mixins: [myMixin]
})
var component = new Component() // => "hello from mixin!"
// define a mixin object
var myMixin = {
created: function () {
this.hello()
},
methods: {
hello: function () {
console.log('hello from mixin!')
}
}
}
// define a mixin object
var myMixinTwo = {
methods: {
hello: function () {
console.log('hello from mixin 2!')
}
}
}
// define a component that uses this mixin
var Component = Vue.extend({
mixins: [myMixin, myMixinTwo]
})
var component = new Component() // => "hello from mixin!"
<template>
<div class="content">
<p class="text">Lorem ipsum</p>
<p class="text">Lorem ipsum</p>
<p class="text">{{message}}</p>
<p class="text">Lorem ipsum</p>
<p class="text">Lorem ipsum</p>
</div>
</template>
function render() {
const children = []
for (let i = 0; i < 5; i++) {
children.push(h('p' , {
class: 'text'
}, i === 2 ? this.message : 'Lorum ipsum'))
}
return h('div', { id: 'content' }, children)
}
<p>Hello {name}!</p>
p(changed, ctx){
if(changed.name){
set_data(t1, ctx.name);
}
}
<template>
<div class="content">
<p class="text">Lorem ipsum</p>
<p class="text">Lorem ipsum</p>
<p class="text">{{message}}</p>
<p class="text">Lorem ipsum</p>
<p class="text">Lorem ipsum</p>
</div>
</template>
(in this benchmark)
const state = Vue.observable({ count: 0 })
const Demo = {
render(h) {
return h('button', {
on: { click: () => { state.count++ }}
}, `counter — ${state.count}`)
}
}
<template>
<form @submit="handleSubmit">
<label>
<span>Note:</span>
<input v-model="currentNote" @input="handleNoteInput">
</label>
<button type="submit">Send</button>
</form>
</template>
<script>
import { ref, watch } from "vue";
export default {
props: ["divRef"],
setup(props, context) {
const currentNote = ref("");
const handleNoteInput = e => {
const val = e.target.value && e.target.value.toUpperCase()[0];
const validNotes = ["A", "B", "C", "D", "E", "F", "G"];
currentNote.value = validNotes.includes(val) ? val : "";
};
const handleSubmit = e => {
context.emit("note-sent", currentNote.value);
currentNote.value = "";
e.preventDefault();
};
return {
currentNote,
handleNoteInput,
handleSubmit,
};
}
};
</script>
export const outerCount = ref(0)
// где-то в компоненте Example.vue
<template>
<button @click="onClick">счётчик — {{count}}</button>
<template>
<script>
import {outerCount} from "foo.js"
const Example = {
setup(props, { attrs }) {
const count = outerCount;
function onClick() {
count.value++;
}
}
}
</script>
const obj = reactive({ count: 0 })
const count = ref(0)
// стиль 1: отдельные значения
let x = 0
let y = 0
function updatePosition(e) {
x = e.pageX
y = e.pageY
}
// --- сравниваем с ---
// стиль 2: объект
const pos = {
x: 0,
y: 0
}
function updatePosition(e) {
pos.x = e.pageX
pos.y = e.pageY
}
function useMousePosition() {
const pos = reactive({
x: 0,
y: 0
})
// ...
return pos
}
export default {
setup() {
// реактивность потеряна!
const { x, y } = useMousePosition()
return {
x,
y
}
// реактивность потеряна!
return {
...useMousePosition()
}
// реактивность не потеряна
return {
pos: useMousePosition()
}
}
}
function useMousePosition() {
const pos = reactive({
x: 0,
y: 0
})
// ...
return toRefs(pos)
}
// x & y are now refs!
const { x, y } = useMousePosition()
const count = ref(0)
watch(() => console.log(count.value))
// -> logs 0
setTimeout(() => {
count.value++
// -> logs 1
}, 100)
watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => {
/* ... */
})
const stop = watch(() => { /* ... */ })
// later
stop()
// event-bus.js
import Vue from 'vue';
const EventBus = new Vue();
export default EventBus;
//vue/src/core/instance/index.js
import { initMixin } from './init'
import { stateMixin } from './state'
import { renderMixin } from './render'
import { eventsMixin } from './events'
import { lifecycleMixin } from './lifecycle'
import { warn } from '../util/index'
function Vue (options) {
if (process.env.NODE_ENV !== 'production' &&
!(this instanceof Vue)
) {
warn('Vue is a constructor and should be called with the `new` keyword')
}
this._init(options)
}
initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)
export default Vue
export default class PubSub{
private listeners:Map<string,EventListener[]> = new Map();
addEventListener(event:string,listener:EventListener){
const listeners = this.listenerts.get(event)||[];
this.listenerts.set([...listeners, listener]);
}
removeEventListener(event:string,listener?:EventListener){
if(!listener)
this.listenerts.remove(event);
this.listenerts.set(this.listeners.filter(item=>item!==listener]);
}
dispatch(event:string, data?:any){
const listeners = this.listenerts.get(event)||[];
listeners.forEach(item=>item.handleEvent(data));
}
}