達人教學pug安裝
https://medium.com/@NorthBei/%E5%A6%82%E6%9E%9C%E4%BD%A0%E6%98%AF%E5%B8%B8%E5%88%87%E7%89%88%E7%9A%84%E5%89%8D%E7%AB%AF%E5%B7%A5%E7%A8%8B%E5%B8%AB-%E4%BD%A0%E4%B8%80%E5%AE%9A%E8%A6%81%E7%9F%A5%E9%81%93pug-8b2cbc0a784c
pug官網
https://pugjs.org/zh-cn/api/getting-started.html
timeline-pug使用實例
https://codepen.io/lebedevdesigns/pen/KQZYjo
https://codepen.io/bcarvalho/pen/RZqmZX
https://freefrontend.com/css-timelines/
angular→typescript
vue→sentry(Tracking Runtime Errors)
数据绑定最常见的形式就是使用“Mustache”语法 (双大括号) //這被稱為模板語言,還有個handlebarsjs也是模板語言
還可以在雙大括號中做運算
{{ number + 1 }} //計算 {{ ok ? 'YES' : 'NO' }} //三元表达式 {{ message.split('').reverse().join('') }} //程式運算 <div v-bind:id="'list-' + id"></div> //字串加變數
但以下兩例是無法執行的
<!-- 这是语句,不是表达式 --> {{ var a = 1 }} <!-- 流控制也不会生效,请使用三元表达式 --> {{ if (ok) { return message } }}1.id="app"
需注意id="app" 一定要配合divㄝ, header, main, nav,...元素使用(似乎是他的規則)
<div id="app"> {{ message }} </div> |
var app = new Vue({ el: '#app', data: { message: 'Hello Vue!' } }) |
<div id="app-2"> <span v-bind:title="message"> 鼠标悬停几秒钟查看此处动态绑定的提示信息! </span> </div> |
var app2 = new Vue({ el: '#app-2', data: { message: '页面加载于 ' + new Date().toLocaleString() } }) |
修改title方式 → app2.message = '新消息'
在布尔特性的情况下,它们的存在即暗示为
true
,v-bind
工作起来略有不同,在这个例子中:<button v-bind:disabled="isButtonDisabled">Button</button>
|
如果
isButtonDisabled
的值是 null
、undefined
或 false
,则 disabled
特性甚至不会被包含在渲染出来的 <button>
元素中。
3.v-if,相應的還有v-if-else, v-else
<div id="app-3"> <p v-if="seen">现在你看到我了</p> </div> |
var app3 = new Vue({ el: '#app-3', data: { seen: true } }) |
如果想切换多个元素,此时可以把一个
<template>
元素当做不可见的包裹元素,并在上面使用 v-if
。最终的渲染结果将不包含 <template>
元素。<template v-if="ok"> <h1>Title</h1> <p>Paragraph 1</p> <p>Paragraph 2</p> </template>
v-else
元素必须紧跟在带 v-if
或者 v-else-if
的元素的后面,否则它将不会被识别
类似于
v-else
,v-else-if
也必须紧跟在带 v-if
或者 v-else-if
的元素之后。<div v-if="type === 'A'"> A </div> <div v-else-if="type === 'B'"> B </div> <div v-else-if="type === 'C'"> C </div> <div v-else> Not A/B/C </div> |
v-if ensures that event listeners and child components inside the conditional block are properly destroyed and re-created during toggles. I
f the condition is false on initial render, it will not do anything - the conditional block won’t be rendered until the condition becomes true for the first time.
vs
v-show The usage is largely the same to v-if. The element is always rendered regardless of initial condition, with CSS-based toggling.(不論怎樣都會render, 他只是利用css使顯示不同)
Note that
v-show
doesn’t support the <template>
element, nor does it work with v-else
.
比較後的結論 v-if
has higher toggle costs while v-show
has higher initial render costs. So prefer v-show
if you need to toggle something very often, and prefer v-if
if the condition is unlikely to change at runtime.
※v-if 与 v-for 一起使用 is not recommended.
首先了解一下 filter vs map (他們大致相同,只在return內容為判別式時,會不同)
首先了解一下 filter vs map (他們大致相同,只在return內容為判別式時,會不同)
Filter receives the same arguments as map, and works very similarly. The only difference is that the callback needs to return either true or false. If it returns true then the array keeps that element and if it returns false the element is filtered out.
下面舉例:
filter會以array回傳符合條件的值
map會以array回傳符合結果true或false
詳細介紹在這 https://medium.com/@joomiguelcunha/learn-map-filter-and-reduce-in-javascript-ea59009593c4
再來進入正題,
To filter items in a list (e.g.
To avoid rendering a list if it should be hidden (e.g.
詳細介紹在這 https://vuejs.org/v2/style-guide/#Avoid-v-if-with-v-for-essential
下面舉例:
const songs=[1,2,3]
const a= songs.filter((value,index,array) => {
return value % 2 ===0;
})
console.log(a); //[2]
console.log(songs); //[1,2,3]
const songs=[1,2,3]
const a= songs.map((value,index,array) => {
return value % 2 ===0;
})
console.log(a); //[false,true,false]
console.log(songs); //[1,2,3]
詳細介紹在這 https://medium.com/@joomiguelcunha/learn-map-filter-and-reduce-in-javascript-ea59009593c4
再來進入正題,
To filter items in a list (e.g.
v-for="user in users" v-if="user.isActive"
). In these cases, replace users
with a new computed property that returns your filtered list (e.g. activeUsers
).To avoid rendering a list if it should be hidden (e.g.
v-for="user in users" v-if="shouldShowUsers"
). In these cases, move the v-if
to a container element (e.g. ul
, ol
).詳細介紹在這 https://vuejs.org/v2/style-guide/#Avoid-v-if-with-v-for-essential
4.v-for="自命名陣列元素 in/of 陣列名稱"
<div id="app-4"> <ol> <li v-for="todo in todos"> {{ todo.text }} </li> </ol> </div> |
var app4 = new Vue({ el: '#app-4', data: { todos: [ { text: '学习 JavaScript' }, { text: '学习 Vue' }, { text: '整个牛项目' } ] } }) |
在控制台里,输入
app4.todos.push({ text: '新项目' })
,你会发现列表最后添加了一个新项目。
Inside
v-for
blocks we have full access to parent scope properties. v-for
also supports an optional second argument for the index of the current item.<ul id="example-2"> <li v-for="(item, index) in items"> {{ parentMessage }} - {{ index }} - {{ item.message }} </li> </ul> |
var example2 = new Vue({ el: '#example-2', data: { parentMessage: 'Parent', items: [ { message: 'Foo' }, { message: 'Bar' } ] } }) |
- v-for with an Object,和陣列的形式相比,他又多了一個key參數可添加
<ul id="v-for-object" class="demo"> <li v-for="(value, key, index) in object">{{ index }}. {{ key }}: {{ value }} </li></ul>
new Vue({ el: '#v-for-object', data: { object: { firstName: 'John', lastName: 'Doe', age: 30 } } }) |
結果為
- 0.firstName:John
- 1.lastName:Doe
- 2.age:30
其排序是依據Object.keys()(取得物件的鍵值,組成陣列後回傳。)
另外,v-for還可搭配v-bind:key建立唯一值屬性
<div v-for="item in items" :key="item.id"> <!-- 内容 --> </div>
※array相關method
首先mutation methods:
首先mutation methods:
push() 添加一個或多個元素至陣列的末端,並且回傳陣列的新長度。
var animals = ['pigs', 'goats', 'sheep'];
console.log(animals.push('cows'));
// expected output: 4
console.log(animals);
// expected output: Array ["pigs", "goats", "sheep", "cows"]
pop() 删除并返回数组的最后一个元素。
var arr = new Array(3)
arr[0] = "George"
arr[1] = "John"
arr[2] = "Thomas"
document.write(arr) //George,John,Thomas
document.write(arr.pop()) //Thomas
document.write(arr) //George,John
shift() 把数组的第一个元素从其中删除,并返回第一个元素的值。 (與pop()類似)
unshift() 可向数组的开头添加一个或更多元素,并返回新的长度。
document.write(arr + "<br />") //George,John,Thomas
document.write(arr.unshift("William") + "<br />") //4
document.write(arr) //William,George,John,Thomas
splice(index,delNum,item1,.....,itemX) 向/从数组中添加/删除项目,然后返回被删除的项目。
index 必需。整数,规定添加/删除项目的位置,使用负数可从数组结尾处规定位置。
delNum 必需。要删除的项目数量。如果设置为 0,则不会删除项目。
item1,...,itemX 可选。向数组添加的新项目
document.write(arr + "<br />") //George,John,Thomas,James,Adrew,Martin
arr.splice(2,3,"William")
document.write(arr) //George,John,William,Martin
sort() 對陣列元素進行排序
reverse() Reverse the order of the elements in an array
var a = ['one', 'two', 'three'];
var reversed = a.reverse();
console.log(a); // ['three', 'two', 'one'] 注意拉!a已經被反轉囉,上面的其他method機制也是這樣的,所以才會叫做mutation methods, 因為mutate the original array
console.log(reversed); // ['three', 'two', 'one']
v.s. non-mutating methods
which do not mutate the original array but always return a new array.
which do not mutate the original array but always return a new array.
◆filter()
◆concat(arrayX,arrayX,......,arrayX) 用于连接两个或多个数组。参数可以是具体的值,也可以是数组对象。可以是任意多个。
var a = [1,2,3];
document.write(a.concat(4,5)); //[1,2,3,4,5]
var arr = new Array(3)
arr[0] = "George"
arr[1] = "John"
arr[2] = "Thomas"
var arr2 = new Array(3)
arr2[0] = "James"
arr2[1] = "Adrew"
arr2[2] = "Martin"
var arr3 = new Array(2)
arr3[0] = "William"
arr3[1] = "Franklin"
document.write(arr.concat(arr2,arr3)) //George,John,Thomas,James,Adrew,Martin,William,Franklin
◆slice([begin[, end]]) 提取start索引值到end索引值維新陣列,但不包含至end索引
var fruits = ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango'];
var citrus = fruits.slice(1, 3); // citrus contains ['Orange','Lemon']
◆concat(arrayX,arrayX,......,arrayX) 用于连接两个或多个数组。参数可以是具体的值,也可以是数组对象。可以是任意多个。
var a = [1,2,3];
document.write(a.concat(4,5)); //[1,2,3,4,5]
var arr = new Array(3)
arr[0] = "George"
arr[1] = "John"
arr[2] = "Thomas"
var arr2 = new Array(3)
arr2[0] = "James"
arr2[1] = "Adrew"
arr2[2] = "Martin"
var arr3 = new Array(2)
arr3[0] = "William"
arr3[1] = "Franklin"
document.write(arr.concat(arr2,arr3)) //George,John,Thomas,James,Adrew,Martin,William,Franklin
◆slice([begin[, end]]) 提取start索引值到end索引值維新陣列,但不包含至end索引
var fruits = ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango'];
var citrus = fruits.slice(1, 3); // citrus contains ['Orange','Lemon']
由于 JavaScript 的限制,Vue 不能检测以下变动的数组:
- 当你利用索引直接设置一个项时,例如:
vm.items[indexOfItem] = newValue
可改用以下三種方式,則為響應式
Vue.set(vm.items, indexOfItem, newValue)
vm.$set(vm.items, indexOfItem, newValue) //這個寫法不過是上方那個全域寫法的別名
vm.items.splice(indexOfItem, 1, newValue) - 当你修改数组的长度时,例如:
vm.items.length = newLength
可改用下方寫法,則為響應式
vm.items.splice(newLength)
var vm = new Vue({ data: { items: ['a', 'b', 'c'] } }) vm.items[1] = 'x' // 不是响应性的 vm.items.length = 2 // 不是响应性的 |
再一次由於 JavaScript 的限制,Vue 不能检测屬性(property)的添加與刪除:
var vm = new Vue({ data: { a: 1 } }) // `vm.a` is now reactive vm.b = 2 // `vm.b` is NOT reactive
Vue does not allow dynamically adding new root-level reactive properties to an already created instance. However, it’s possible to add reactive properties to a nested object using the
Vue.set(object, key, value)
method.
如下例子
var vm = new Vue({ data: { userProfile: { name: 'Anika' } } })
You could add a new
age
property to the nested userProfile
object with:Vue.set(vm.userProfile, 'age', 27) //等於 vm.$set(vm.userProfile, 'age', 27)
Sometimes you may want to assign a number of new properties to an existing object, for example using
Object.assign()
or _.extend()
. In such cases, you should create a fresh object with properties from both objects. So instead of:Object.assign(vm.userProfile, { age: 27, favoriteColor: 'Vue Green' }) |
You would add new, reactive properties with:
vm.userProfile = Object.assign({}, vm.userProfile, { age: 27, favoriteColor: 'Vue Green' }) |
但非感應式寫法,會在感應式寫法接收到變動時,跟著改變成修改過的值。(在網頁console裡做修改測試時的發現)
P.S.
Object.assign() 簡單說一下,它的功能可以是複製物件,也可以是合併物件,詳細請見https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
P.S. Symbol 类型 使命名為唯一,類似字符串的類型,但是第七種類型,前六种是:
P.S. _.extend()方法是Underscore.js库提供的一个方法,作用是将sources对象中的所有属性拷贝到destination对象中,并返回destination对象。
undefined
、null
、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。 更多見: http://es6.ruanyifeng.com/#docs/symbolP.S. _.extend()方法是Underscore.js库提供的一个方法,作用是将sources对象中的所有属性拷贝到destination对象中,并返回destination对象。
_.extend(destination, *sources)
還可以配合compute, methods,如下
<li v-for="n in evenNumbers">{{ n }}</li>
|
data: { numbers: [ 1, 2, 3, 4, 5 ] }, computed: { evenNumbers: function () { return this.numbers.filter(function (number) { return number % 2 === 0 }) } } |
<li v-for="n in even(numbers)">{{ n }}</li>
|
data: { numbers: [ 1, 2, 3, 4, 5 ] }, methods: { even: function (numbers) { return numbers.filter(function (number) { return number % 2 === 0 }) } } |
<div> <span v-for="n in 10">{{ n }} </span> // v-for can also take an integer. In this case it will repeat the template that many times. </div>
結果呈現 1 2 3 4 5 6 7 8 9 10
<ul> <template v-for="item in items"> <li>{{ item.msg }}</li> <li class="divider" role="presentation">XXX</li> </template> </ul> |
- 1
- XXX
- 2
- XXX
- ...
vs
<ul v-for="item in items"> <li>{{ item.msg }}</li> <li class="divider" role="presentation">XXX</li> </ul> |
- 1
- XXX //下面會有空隙
- 2
- XXX //下面會有空隙
- 3
- ... //下面會有空隙
v-for
has a higher priority than v-if
v-for with a Component這部分先跳過,等看完component再回來看 (
https://vuejs.org/v2/guide/list.html)
5.v-on:click="reverseMessage" ,印象中也可以寫成 @click="reverseMessage"
<div id="app-5"> <p>{{ message }}</p> <button v-on:click="reverseMessage">逆转消息</button> </div> |
var app5 = new Vue({ el: '#app-5', data: { message: 'Hello Vue.js!' }, methods: { reverseMessage: function () { this.message = this.message.split('').reverse().join('') } } }) |
再一個例子
<div id="example-1"> <button v-on:click="counter += 1">Add 1</button> <p>The button above has been clicked {{ counter }} times.</p> </div> |
var example1 = new Vue({
el: '#example-1',
data: {
counter: 0
}
})
|
再來一個例子以前,首先了解一下javascript的型別強制轉換,
https://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/
簡單的說結果如下:
Argument Type | Result |
Undefined | false |
Null | false |
Boolean | The result equals the input argument (no conversion). |
Number | The result is false if the argument is +0, −0, or NaN; otherwise the result is true. |
String | The result is false if the argument is the empty String (its length is zero); otherwise the result is true. |
Object | true. |
This is the formula JavaScript uses to classify values as truthy (
true
, "potato"
, 36
, [1,2,4]
and {a:16}
) or falsey (false
, 0
, ""
, null
and undefined
).(我自己的想法是除了這幾個以外,都是true,這樣比較容易記)<div id="example-2"> <!-- `greet` is the name of a method defined below --> <button v-on:click="greet">Greet</button> </div>
var example2 = new Vue({ el: '#example-2', data: { name: 'Vue.js' }, // define methods under the `methods` object methods: { greet: function (event) { // `this` inside methods points to the Vue instance alert('Hello ' + this.name + '!') // `event` is the native DOM event if (event) { //Event Objects: When an event occur in HTML, the event belongs to a certain event object, like a mouse click event belongs to the MouseEvent object. alert(event.target.tagName) //BUTTON } } } }) // you can invoke methods in JavaScript too example2.greet() // => 'Hello Vue.js!' ,不執行 if (event)的內容,因為該event 是指event object,在此處為[object MouseEvent]
Sometimes we also need to access the original DOM event in an inline statement handler. You can pass it into a method using the special
$event
variable:<button v-on:click="warn('Form cannot be submitted yet.', $event)"> Submit </button> |
// ... methods: { warn: function (message, event) { // now we have access to the native event if (event) event.preventDefault() alert(message) } } |
待看https://vuejs.org/v2/guide/events.html#Listening-to-Events
Unlike the other modifiers, which are exclusive to native DOM events, the
.once
modifier can also be used on component events. If you haven’t read about components yet, don’t worry about this for now.
Event Modifiers
.stop
.prevent
.capture
.self
.once
.passive
<!-- the click event's propagation will be stopped --> <a v-on:click.stop="doThis"></a> <!-- the submit event will no longer reload the page --> <form v-on:submit.prevent="onSubmit"></form> <!-- modifiers can be chained --> <a v-on:click.stop.prevent="doThat"></a> <!-- just the modifier --> <form v-on:submit.prevent></form> <!-- use capture mode when adding the event listener --> <!-- i.e. an event targeting an inner element is handled here before being handled by that element --> <div v-on:click.capture="doThis">...</div> <!-- only trigger handler if event.target is the element itself --> <!-- i.e. not from a child element --> <div v-on:click.self="doThat">...</div>
<!-- the click event will be triggered at most once --> <a v-on:click.once="doThis"></a>
<!-- the scroll event's default behavior (scrolling) will happen --> <!-- immediately, instead of waiting for `onScroll` to complete --> <!-- in case it contains `event.preventDefault()` --> <div v-on:scroll.passive="onScroll">...</div>
5.5 Key Modifiers → v-on:keyup.xxx
When listening for keyboard events, we often need to check for common key codes.
<!-- only call `vm.submit()` when the `keyCode` is 13 --> <input v-on:keyup.13="submit">
Vue provides aliases for the most commonly used keys:
.enter
.tab
.delete
(captures both “Delete” and “Backspace” keys).esc
.space
.up
.down
.left
.right
<!-- same as above --> <input v-on:keyup.enter="submit"> <!-- also works for shorthand --> <input @keyup.enter="submit"> |
// enable `v-on:keyup.f1` Vue.config.keyCodes.f1 = 112 |
via
KeyboardEvent.key
as modifiers by converting them to kebab-case:<input @keyup.page-down="onPageDown">
|
$event.key === 'PageDown'
But a few keys (.esc and all arrow keys) have inconsistent key values in IE9, their built-in aliases should be preferred if you need to support IE9!
kebab-case (短橫線命名) v.s. camelCased (驼峰式)
KeyboardEvent.key v.s. InputEvent.data
都是Read only。
簡單的說就是後者只用在input類,例如a,4,.,,等等,而enter或backspace會傳null,space則是空字串" "。而前者除此之外,像control會回傳control
let textarea = document.getElementById('test-target'),
consoleLog = document.getElementById('console-log'),
btnClearConsole = document.getElementById('btn-clear-console');
function logMessage(message) {
let p = document.createElement('p');
p.appendChild(document.createTextNode(message));
consoleLog.appendChild(p);
}
textarea.addEventListener('keydown', (e) => {
if (!e.repeat)
logMessage(`first keydown event. key property value is "${e.key}"`);
else
logMessage(`keydown event repeats. key property value is "${e.key}"`);
});
textarea.addEventListener('beforeinput', (e) => {
logMessage(`beforeinput event. you are about inputing "${e.data}"`);
});
textarea.addEventListener('input', (e) => {
logMessage(`input event. you have just inputed "${e.data}"`);
});
textarea.addEventListener('keyup', (e) => {
logMessage(`keyup event. key property value is "${e.key}"`);
});
btnClearConsole.addEventListener('click', (e) => {
let child = consoleLog.firstChild;
while (child) {
consoleLog.removeChild(child);
child = consoleLog.firstChild;
}
});
System Modifier Keys
You can use the following modifiers to trigger mouse or keyboard event listeners only when the corresponding modifier key is pressed:
.ctrl
.alt
.shift
.meta
<!-- Alt + C --> <input @keyup.alt.67="clear"> <!-- Ctrl + Click --> <div @click.ctrl="doSomething">Do something</div>
system modifier 可搭配 .exact (modifier / 修飾符)
<!-- this will fire even if Alt or Shift is also pressed --> <button @click.ctrl="onClick">A</button> <!-- this will only fire when Ctrl and no other keys are pressed --> <button @click.ctrl.exact="onCtrlClick">A</button> <!-- this will only fire when no system modifiers are pressed --> <button @click.exact="onClick">A</button>
mouse button modifiers 限制滑鼠按的是左鍵右鍵或中間
.left
.right
.middle
6.v-model ,當用在一個元素(非array)時,作用可說是與v-bind:value=相同,基本只用在表單元素,如input,且v-model優先級更高,所以在一個元素時,v-model不會與v-bind:value=同時使用。
#TEXT
<div id="app-6"> <p>{{ message }}</p> <input v-model="message"> </div> |
var app6 = new Vue({ el: '#app-6', data: { message: 'Hello Vue!' } }) |
想要p元素裡出來的就是輸入的文字,用""。
<div id="app">
<input id="a2" v-model="message" placeholder="edit me">
<p>Message is: {{ message }}</p>
</div>
<script>
new Vue({
el:'#app',
data:{
message:""
}
})
</script>
#CHECKBOX
v-model會忽略最初的表單設定值如 checked or selected attributes. 如果要最初值,那要自己用JS添加。(v-bind:value也是,不過在表單上都用v-modal,所以就直接說v-modal了)
<div id="app">
<input type="checkbox" id="checkbox" v-model="checked">
<label for="checkbox">{{ checked }}</label>
</div>
<script>
new Vue({
el:'#app',
data:{
checked:this.modal
}
})
</script>
<input type="checkbox" id="checkbox" v-model="checked">
<label for="checkbox">{{ checked }}</label>
</div>
<script>
new Vue({
el:'#app',
data:{
checked:this.modal
}
})
</script>
像上述例子,最初就只會有checkbox那個框,label裡則什麼也沒有。
較特別的是,v-modal 在radio, checkbox, select中不像v-bind:value,較像v-bind:name。
注意!用javascript取該元素value或name都為空,除非在vue instance已經有指向他們。
<div id='example-3'> <input type="checkbox" id="jack" value="Jack" v-model="checkedNames"> <label for="jack">Jack</label> <input type="checkbox" id="john" value="John" v-model="checkedNames"> <label for="john">John</label> <input type="checkbox" id="mike" value="Mike" v-model="checkedNames"> <label for="mike">Mike</label> <br> <span>Checked names: {{ checkedNames }}</span> </div>
new Vue({ el: '#example-3', data: { checkedNames: [] } })
↑會將checked的value存入checkedNames[]
<input type="radio" id="one" value="One" v-model="picked"> <label for="one">One</label> <br> <input type="radio" id="two" value="Two" v-model="picked"> <label for="two">Two</label> <br> <span>Picked: {{ picked }}</span>
new Vue({
el: '#example-3',
data: {
picked:''
}
})
↑會將checked的value存入picked
<select v-model="selected"> <option disabled value="">Please select one</option> <option>A</option> <option>B</option> <option>C</option> </select> <span>Selected: {{ selected }}</span> |
new Vue({ el: '...', data: { selected: '' } })
↑如果最初的selected內容不在任何可選的選項中,那就provide a disabled option with an empty value.
這樣設計的原因是→If the initial value of your v-model expression does not match any of the options, the <select> element will render in an “unselected” state. On iOS this will cause the user not being able to select the first item because iOS does not fire a change event in this case.
<select v-model="selected"> <option v-for="option in options" v-bind:value="option.value"> {{ option.text }} </option> </select> <span>Selected: {{ selected }}</span>
new Vue({ el: '...', data: { selected: 'A', options: [ { text: 'One', value: 'A' }, { text: 'Two', value: 'B' }, { text: 'Three', value: 'C' } ] } }) |
最後來點練習
<!-- `picked` is a string "a" when checked --> <input type="radio" v-model="picked" value="a"> <!-- `toggle` is either true or false --> <input type="checkbox" v-model="toggle"> //在vue的設定中會傳true或false的值,但如果檢查該元素的value,那麼不論checked or not「都」會傳on的值。因為vue的v-modal雖似v-bind:value,但不是真的value,我想這樣的寫法在傳送表單時應該也有它自己的一套方式 <!-- `selected` is a string "abc" when the first option is selected --> <select v-model="selected"> <option value="abc">ABC</option> </select>
※有個辦法改變checkbox checked時回傳不是true或false→在input裡加true-value="yes"
false-value="no",如此在js會得到
// when checked:
vm.toggle === 'yes'
// when unchecked:
vm.toggle === 'no'
,但如果想用他的value值傳遞給後端,那不是那麼的有意義,因為checkbox只傳checked的值。這裡只是告知一下有true-value="yes" false-value="no"的寫法,要用這個不如用input radio就好。
複習
1.
<input type="radio" v-model="pick" v-bind:value="a"> //// when checked: vm.pick === vm.a
2.
<select v-model="selected"> <option v-bind:value="{ number: 123 }">123</option> </select> |
// when selected: typeof vm.selected // => 'object' vm.selected.number // => 123 |
- v-model.lazy //在默认情况下, v-model 在 input 事件中同步输入框的值与数据 (除了 上述 IME 部分),但你可以添加一个修饰符 lazy ,从而转变为在 change 事件中同步
- v-model.number //自动将用户的输入值转为 Number 类型
- v-model.trim //自动过滤用户输入的首尾空格
有句話說,<input v-model="something">其实是<input v-bind:value="something" v-on:input="something = $event.target.value">
7.区分v-bind和v-model
vue的模板采用DOM模板,也就是说它的模板可以当做DOM节点运行,在浏览器下不报错,绑定数据有三种方式,一种是插值(下面程式先補充個利用js插入插植的方法),也就是{{name}}的形式,一种是v-bind,还有一种是v-model。
要区分v-bind和v-model,只需要记住三句话:
1. v-bind是数据绑定,没有双向绑定效果,但不一定在表单元素上使用,任何有效元素上都可以使用;3. 当v-bind和v-model同时用在一个元素上时,它们各自的作用没变,但v-model优先级更高,而且需区分这个元素是单个的还是一组出现的。
更多詳細內容請見→https://www.tangshuang.net/3507.html
8.
Object.freeze()
,这会阻止修改现有的属性,也意味着响应系统无法再追踪变化。var obj = { foo: 'bar' } Object.freeze(obj) new Vue({ el: '#app', data: obj }) |
<div id="app"> <p>{{ foo }}</p> <!-- 这里的 `foo` 不会更新! --> <button v-on:click="foo = 'baz'">Change it</button> </div> |
9.watch屬性在監聽對象的數值發生改變時才會觸發。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。
除了访问和展示一个 API,axios 還可以在取得權限後发布/编辑/删除请求(Serverless Function 通信)
疑問: Serverless 相關資料還沒看
另外
Fetch API 是一个用于此类请求的强大的原生 API。 Fetch API 其中的一个好处是你不需要在使用它的时候额外加载一个外部资源。但它还没有被浏览器完全支持,所以現階段大家更喜欢 axios 多一些。
提及filter
Filter 適於文字格式處理等簡單的狀況,而較複雜的資料處理則適合使用 Computed。
可使用「|」(pipe)聯集多個 Filter,要注意順序,愈靠左愈先執行。
methods每次都會計算。可寫作<p>reversed message: "{{ reversedMessage() }}"</p>
computed值在依賴的對象發生改變時才會重新計算,否則會調用之前的緩存。可寫作<p>reversed message: "{{ reversedMessage }}"</p>。須注意的是
請看https://www.jianshu.com/p/709a7bd05da4
<div id="watch-example"> <p> Ask a yes/no question: <input v-model="question"> </p> <p>{{ answer }}</p> </div>
<!-- 因为 AJAX 库和通用工具的生态已经相当丰富,Vue 核心代码没有重复 --> <!-- 提供这些功能以保持精简。这也可以让你自由选择自己更熟悉的工具。 --> <script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/lodash@4.13.1/lodash.min.js"></script> <script> var watchExampleVM = new Vue({ el: '#watch-example', data: { question: '', answer: 'I cannot give you an answer until you ask a question!' }, watch: { // 如果 `question` 发生改变,这个函数就会运行 question: function (newQuestion, oldQuestion) { this.answer = 'Waiting for you to stop typing...' this.debouncedGetAnswer() } }, created: function () { // `_.debounce` 是一个通过 Lodash 限制操作频率的函数。 // 在这个例子中,我们希望限制访问 yesno.wtf/api 的频率 // AJAX 请求直到用户输入完毕才会发出。想要了解更多关于 // `_.debounce` 函数 (及其近亲 `_.throttle`) 的知识, // 请参考:https://lodash.com/docs#debounce this.debouncedGetAnswer = _.debounce(this.getAnswer, 500) }, methods: { getAnswer: function () { if (this.question.indexOf('?') === -1) { this.answer = 'Questions usually contain a question mark. ;-)' return } this.answer = 'Thinking...' var vm = this axios.get('https://yesno.wtf/api') .then(function (response) { vm.answer = _.capitalize(response.data.answer)
}) .catch(function (error) { vm.answer = 'Error! Could not reach the API. ' + error }) } } }) </script>
//_.capitalize來自lodash,作用是转换字符串首字母为大写,剩下为小写。
使用 watch
选项允许我们执行异步操作 (访问一个 API),限制执行该操作的频率,并在得到最终结果前,设置中间状态。这些都是计算属性无法做到的。
待看
https://blog.coding.net/blog/the-difference-between-throttle-and-debounce-in-underscorejs,其中源码注解還沒看,
想象每天上班大厦底下的电梯。把电梯完成一次运送,类比为一次函数的执行和响应。假设电梯有两种运行策略
https://blog.coding.net/blog/the-difference-between-throttle-and-debounce-in-underscorejs,其中源码注解還沒看,
throttle
和 debounce
是解决请求和响应速度不匹配问题的两个方案。二者的差异在于选择不同的策略。下方說明想象每天上班大厦底下的电梯。把电梯完成一次运送,类比为一次函数的执行和响应。假设电梯有两种运行策略
throttle
和 debounce
,超时设定为15秒,不考虑容量限制。throttle
策略的电梯。保证如果电梯第一个人进来后,15秒后准时运送一次,不等待。如果没有人,则待机。debounce
策略的电梯。如果电梯里有人进来,等待15秒。如果又人进来,15秒等待重新计时,直到15秒超时,开始运送。
要會
axios
Using Axios to Consume APIs (取代ajax)
第一步,先引入axios的cdn
第二步,
第三步使用陣列
axios
Using Axios to Consume APIs (取代ajax)
第一步,先引入axios的cdn
第二步,
new Vue({ el: '#app', data () { return { info: null } }, mounted () { axios .get('https://api.coindesk.com/v1/bpi/currentprice.json') .then(response => (this.info = response)) //response.data.chartName } }) |
<div id="app"> <h1>Bitcoin Price Index</h1> <section v-if="errored"> <p>We're sorry, we're not able to retrieve this information at the moment, please try back later</p> </section> <section v-else> <div v-if="loading">Loading...</div> <div v-else v-for="currency in info" class="currency" > {{ currency.description }}: <span class="lighten"> <span v-html="currency.symbol"></span>{{ currency.rate_float | currencydecimal }} </span> </div> </section> </div> |
new Vue({ el: '#app', data () { return { info: null, loading: true, errored: false } }, filters: { currencydecimal (value) { return value.toFixed(2) } }, mounted () { axios .get('https://api.coindesk.com/v1/bpi/currentprice.json') .then(response => { //這個{}也有人在內容物只有一個時用() this.info = response.data.bpi }) .catch(error => { console.log(error) //這裡有沒有;依賴於有沒有分行 this.errored = true }) .finally(() => this.loading = false) } })
除了访问和展示一个 API,axios 還可以在取得權限後发布/编辑/删除请求(Serverless Function 通信)
疑問: Serverless 相關資料還沒看
另外
Fetch API 是一个用于此类请求的强大的原生 API。 Fetch API 其中的一个好处是你不需要在使用它的时候额外加载一个外部资源。但它还没有被浏览器完全支持,所以現階段大家更喜欢 axios 多一些。
提及filter
Filter 適於文字格式處理等簡單的狀況,而較複雜的資料處理則適合使用 Computed。
可使用「|」(pipe)聯集多個 Filter,要注意順序,愈靠左愈先執行。
<div id="app">
<div>${ price | commaFormat | priceFormat }</div>
</div>
var vm = new Vue({
el: '#app',
delimiters: ['${', '}'], // delimiters 傳入一個 array,第一個 index 是左側的表達式,第二個 index 是右側的表達式。因為在其他載入的資料庫中,也許有不是vue卻也用mustache寫法的程式語言,為避免衝突,可適用delimiters自定義表達式的符號。
data: {
price: 9999999
},
Filters: {
priceFormat: function(value) { // 加上 $ 字號
return '$' + value
},
commaFormat: function(value) { // 加上千分位符號
return value.toString().replace(/^(-?\d+?)((?:\d{3})+)(?=\.\d+$|$)/, function (all, pre, groupOf3Digital) {
return pre + groupOf3Digital.replace(/\d{3}/g, ',$&');
})
}
}
});
// 由於部落格會把使用雙花括號的內容吃掉,所以設定 delimiters 以顯示完整程式碼。
methods每次都會計算。可寫作<p>reversed message: "{{ reversedMessage() }}"</p>
computed值在依賴的對象發生改變時才會重新計算,否則會調用之前的緩存。可寫作<p>reversed message: "{{ reversedMessage }}"</p>。須注意的是
Date.now()
不是响应式依赖(reactive dependent),所以放在computed裡,他不會隨著時間變動而觸發,而需使用method進行調用!請看https://www.jianshu.com/p/709a7bd05da4
首先了解一下,關於reversedMessage,下方兩個程式是一樣的意思
<div id="example"> <p>Original message: "{{ message }}"</p> <p>Computed reversed message: "{{ reversedMessage }}"</p> </div>
var vm = new Vue({ el: '#example', data: { message: 'Hello' }, computed: { reversedMessage: function () { return this.message.split('').reverse().join('') } 等同於
} }) |
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar'
},
computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
var names = newValue.split(' ');
this.firstName = names[0];
this.lastName = names[names.length - 1];
}
}
}
})
vm.firstName = 'Jo2hn Doe';
vm.fullName 的值始终取决于
vm.firstName 和 vm.lastName
的值。<!-- template -->
<div id="computed-setter-basic" v-cloak="v-cloak">
<h3 class="title-border">一般情況 computed setter 被觸發的時間點</h3>
<form class="pure-form">
<input type="text" v-model="fullName"/>
</form>
<p>firstName: {{ firstName }} <br/> lastName: {{ lastName }}</p>
</div>
// js
// computed-setter-basic
new Vue({
el: '#computed-setter-basic',
data: {
firstName: 'PJ',
lastName: 'Chen'
},
computed: {
fullName: {
get () {
console.log('computed getter')
return this.firstName + ' ' + this.lastName
},
set (value) {
console.log('computed setter')
this.firstName = value.split(' ')[0]
this.lastName = value.split(' ')[1]
}
}
},
updated () {
console.log('updated')
}
})
當我在 input 中輸入內容時,fullName 會改變,fullName 改變的情況會觸發 setter ,接著,因為我的 setter 中所做的事會變更到 getter 中所觀察的資料,這時候才又觸發 getter 執行,最後重新 updated 畫面。也就是從 setter -> getter -> updated 這樣的過程。總結
- getter 和 setter 彼次觸發的時間點是獨立的。 getter 在大部分的時候是當內部觀察的資料有改變時會被觸發;setter 則是當被觀察的物件本身有改變時會被觸發。
- getter 和setter在畫面中沒有使用到被觀察的物件時,不會被觸發。
10. mount 掛載
var MyComponent = Vue.extend({ template: '<div>Hello!</div>' }) // 创建并挂载到 #app (会替换 #app) new MyComponent().$mount('#app') // 同上 new MyComponent({ el: '#app' }) // 或者,在文档之外渲染并且随后挂载 var component = new MyComponent().$mount() document.getElementById('app').appendChild(component.$el)
11. v-once
只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。
<!-- 单个元素 --> <span v-once>This will never change: {{msg}}</span> <!-- 有子元素 --> <div v-once> <h1>comment</h1> <p>{{msg}}</p> </div> <!-- 组件 --> <my-component v-once :comment="msg"></my-component> <!-- `v-for` 指令--> <ul> <li v-for="i in list" v-once>{{i}}</li> </ul> |
12. v-html
<p>Using mustaches: {{ rawHtml }}</p> <p>Using v-html directive: <span v-html="rawHtml"></span></p> |
Using mustaches: <span style="color: red">This should be red.</span>
Using v-html directive: This should be red.
13.v-bind:class
class 存在与否将取决于数据属性 isActive 的 truthiness,並且
v-bind:class
指令也可以与普通的 class 属性共存<div class="static" v-bind:class="{ active: isActive, 'text-danger': hasError }"> </div>
data: { isActive: true, hasError: false }
或 The bound object doesn’t have to be inline(绑定的数据对象不必内联定义在模板里):
<div v-bind:class="classObject"></div>
|
data: { classObject: { active: true, 'text-danger': false //''應該是因為class名稱有- 才會需要 } } |
或 bind to a computed property
data: { isActive: true, error: null }, computed: { classObject: function () { return { active: this.isActive && !this.error, // !null等於true 'text-danger': this.error && this.error.type === 'fatal' //this.error.type 未定義 } } } |
结果都渲染为:
<div class="static active"></div>
|
除了上述用object的方式外,還可以用 array寫法
<div v-bind:class="[activeClass, errorClass]"></div>
|
data: { activeClass: 'active', errorClass: 'text-danger' } |
<div class="active text-danger"></div>
可加入三元表达式
<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>
这样写将始终添加
errorClass
,但是只有在 isActive
是 truthy 时才添加 activeClass
。
不过,当有多个条件 class 时这样写有些繁琐。所以在数组语法中也可以使用对象语法:
<div v-bind:class="[{ active: isActive }, errorClass]"></div>
|
https://cn.vuejs.org/v2/guide/class-and-style.html
#用在组件上
等看完了 Vue 组件(component)後再回來看
14.v-bind:style 自动侦测并添加相应的浏览器前缀,如 transform
属性名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用单引号括起来) 来命名
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
data: { activeColor: 'red', fontSize: 30 }
直接绑定到一个样式对象通常更好,这会让模板更清晰:
<div v-bind:style="styleObject"></div>
|
data: { styleObject: { color: 'red', fontSize: '13px' } } |
Array可以将多个样式对象应用到同一个元素上:
<div v-bind:style="[baseStyles, overridingStyles]"></div>
|
<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>
15.唯一值
Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。这么做除了使 Vue 变得非常快。key
但也不是所有情況都適合復用,如果你允许用户在不同的登录方式之间切换時,需要添加一个具有唯一值的
key
属性,表示"这两个元素是完全独立的,不要复用它们”。否則在第一個輸入的input值會出現在第二個input中,程式如下。<template v-if="loginType === 'username'"> <label>Username</label> <input placeholder="Enter your username" key="username-input"> </template> <template v-else> <label>Email</label> <input placeholder="Enter your email address" key="email-input"> </template>
注意,
<label>
元素仍然会被高效地复用,因为它们没有添加 key
属性。
16. 插入個render是什麼的說明
https://www.youtube.com/watch?v=GQzn7XRdzxY 很棒的解說
javascript frameworks( like react, angular, vue.js)都是server-side rendering,他會在server端產生HTML,然後傳送到browser
原生的javascript會由browser render,網頁的呈現當html和css解讀完就可以出來,但是這時還沒有js,如果js檔案很大,這時最好改用framework,利用Cloud Function動態生成內容,然後Firebase Hosting 會把它儲存在cdn cache,所以下一個使用者到來後,網頁不用重新生成,local cdn edge會提供內容給他(serve it)
https://www.youtube.com/watch?v=GQzn7XRdzxY 很棒的解說
javascript frameworks( like react, angular, vue.js)都是server-side rendering,他會在server端產生HTML,然後傳送到browser
原生的javascript會由browser render,網頁的呈現當html和css解讀完就可以出來,但是這時還沒有js,如果js檔案很大,這時最好改用framework,利用Cloud Function動態生成內容,然後Firebase Hosting 會把它儲存在cdn cache,所以下一個使用者到來後,網頁不用重新生成,local cdn edge會提供內容給他(serve it)
- TTI (Time to Interactive) 在js被瀏覽器讀取,到使用者可與之互動,之間的讀取時間是凍結的狀態,而這時間被稱為TTI
17.Components Basics
首先寫一個vue.component
// Define a new component called button-counter Vue.component('button-counter', { data: function () { return { count: 0 } }, template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>' })
接著就能把它當作客製的元素,在vue instance中使用
<div id="components-demo"> <button-counter></button-counter> </div>
new Vue({ el: '#components-demo' })
|
小提醒!vue.component必須寫在被使用之前。
Since components are reusable Vue instances, they accept the same options as
new Vue
, such as data
, computed
, watch
, methods
, and lifecycle hooks. The only exceptions are a few root-specific options like el
.data
option must be a function, so that each instance can maintain an independent copy of the returned data object.
There are two types of component registration: global and local.
進一步,可以重複使用的component在重複利用時用props指定其中變數的值:
Vue.component('blog-post', { props: ['title'], template: '<h3>{{ title }}</h3>' })
<blog-post title="My journey with Vue"></blog-post> <blog-post title="Blogging with Vue"></blog-post> <blog-post title="Why Vue is so fun"></blog-post>
最後,可以把上面這個重複的blog-post tag改成array
new Vue({ el: '#blog-post-demo', data: { posts: [ { id: 1, title: 'My journey with Vue' }, { id: 2, title: 'Blogging with Vue' }, { id: 3, title: 'Why Vue is so fun' } ] } })
//原本沒有data,data.posts的內容是json
<blog-post v-for="post in posts" v-bind:key="post.id" v-bind:title="post.title" ></blog-post>
use
new Vue({
el: '#blog-post-demo',
data: {
posts: []
},
created: function () {
// Alias the component instance as `vm`, so that we
// can access it inside the promise function
var vm = this
// Fetch our array of posts from an API
fetch('https://jsonplaceholder.typicode.com/posts')
.then(function (response) {
return response.json()
})
.then(function (data) {
vm.posts = data
})
}
})
v-bind
to dynamically pass props.如此一來接API時posts就可以直接接json使用,如下:new Vue({
el: '#blog-post-demo',
data: {
posts: []
},
created: function () {
// Alias the component instance as `vm`, so that we
// can access it inside the promise function
var vm = this
// Fetch our array of posts from an API
fetch('https://jsonplaceholder.typicode.com/posts')
.then(function (response) {
return response.json()
})
.then(function (data) {
vm.posts = data
})
}
})
先行補充:每個XML文檔都只有一個root element。它包含所有其他元素,因此是所有其他元素的唯一父元素。ROOT elements are also called document elements。在HTML中,根元素是<html>元素
component must have a single root element!
前面以props讓重複使用的component可以是不同的參數應用,並且在body連續的寫入,可改用array更簡潔,如:<blog-post v-for="post in posts" v-bind:key="post.id" v-bind:title="post.title" ></blog-post>,但是如果除了post.title之外,還有post.content, post.publishedAt, post.comments,...,則建議重建為:
<blog-post v-for="post in posts" v-bind:key="post.id" v-bind:post="post"></blog-post>配合下面Vue.component('blog-post', { props: ['post'], template: ` <div> <h3>{{ post.title }}</h3> <div v-html="post.content"></div> </div> ` })
props: ['post'],直接在template裡寫
補充:上方淺粉底處有各有一個`,他是JavaScript’s template literal,在template之後的程式碼一般情況下不能分行,否則會讀取不到,但分行較好閱讀,這時就要用``把code wrap起來,程式碼就可以認得。
專門對``進行說明如下:
專門對``進行說明如下:
console.log('string text line 1\n' +
'string text line 2');
和
console.log(`string text line 1
string text line 2`);
都出現下方結果
// "string text line 1
// string text line 2"
'string text line 2');
和
console.log(`string text line 1
string text line 2`);
都出現下方結果
// "string text line 1
// string text line 2"
如果在``之中要放入變數,那就用${ }把變數wrap即可使用
其他還有更多使用,但就先不提,因為光是一般用法ie就不支援,在更多的用法,又以更多的brower不支援。
如果想用component使整個vue instance改變,那就要用到$emit('自訂事件名稱'):
※自訂事件名稱,會被用在html的v-on:自訂事件名稱="vue.instance.methods名稱"
Trigger an event on the current instance. Any additional arguments will be passed into the listener’s callback function.
首先,撰寫一個用到它的component
1.
Vue.component('example',{
template:`
<div v-on:click="$emit('test')">
測試
</div>
})
2.
Vue.component('blog-post', {
props: ['post'],
template: `
<div class="blog-post">
<h3>{{ post.title }}</h3>
<button v-on:click="$emit('enlarge-text')">
Enlarge text
</button>
<div v-html="post.content"></div>
</div>
`
})
再寫一個含有事件的vue.instance,或是事件要寫在html,那這裡只要寫關鍵的變化值在data property:
→1.含有事件的vue.instance
new Vue({
el:'#app',
methods:{
sayHi:function(){
alert('hi');
}
}
})
→2.事件要寫在html,那這裡只要寫關鍵的變化值在data property
new Vue({
el:"#app",
data:{
posts: [
{ id: 1, title: 'My journey with Vue' },
{ id: 2, title: 'Blogging with Vue' },
{ id: 3, title: 'Why Vue is so fun' }
],
postFontSize:1
}
})
最後補上HTML
1.
<div id="app">
<example v-on:test="sayHi"></example>
</div>
2.
<div id="app">
<div :style="{ fontSize: postFontSize + 'em' }"> //目標元素
<blog-post
v-for="post in posts"
v-bind:key="post.id"
v-bind:post="post"
v-on:enlarge-text="postFontSize += 0.1"> </blog-post> //除了設定觸發事件外,還要加上目標元素
</div>
</div>
ok, 綜上所述,再來一個例子:$emit('自訂事件名稱',第二參數,第三參數,...)
參數將自動轉成vue.instance.methods的參數,而在parent呼叫時,只需v-on:自訂事件名稱="vue.instance.methods.name",不須附上參數(因為$emit已經傳送了參數)
→vue.component裡的data有array它含有三個值,當點擊vue.component中的按鈕時,觸發vue instance的method,methods裡要隨機alert array中的值。
Vue.component('example',{
data:function(){
return {
array1:['Yes','No','Maybe']
}
},
methods:{
give_com:function(){
var a=Math.floor(Math.random()*this.array1.length);
this.$emit('test', this.array1[a]);
}
},
template:`
<div v-on:click="give_com">123</div>
`
})
new Vue({
el:"#app",
methods:{
vue_methods:function(f){
alert(f)
}
}
})
<div id="app">
<example v-on:test="vue_methods">
</example>
</div>
或是 event handler is not a method:
<blog-post ... v-on:enlarge-text="postFontSize += $event" ></blog-post>
直接用$event代表parent.event的參數值,這樣寫不用在Vue.instance再寫methods。
P.S.如果單純只是vue instance下的一般元素使用vue instance的 methods的話可直接call。
※<component></component> + :is, v-model, <slot></slot>
1. <component></component> + :is→
<!-- Component changes when currentTabComponent changes --> <component v-bind:is="currentTabComponent"></component> |
In the example above,
currentTabComponent
can contain either:- the name of a registered component, or
- a component’s options object
→Have you ever needed to switch between various arbitrary components at the same mount point in Vue.js ?
it’s quite simple to do in Vue by using the <component></component> tag.
It just takes a string (or component definition) :is prop. Vue then looks up the component referenced by that string and renders it in place of the <component> tag.
reference: https://alligator.io/vuejs/dynamic-components/ 下面import...export default什麼的看不懂
https://segmentfault.com/q/1010000011186651/a-1020000011187890 也一樣
https://segmentfault.com/q/1010000011186651/a-1020000011187890 也一樣
可再搭配 <keep-alive></keep-alive>
<!-- 失活的组件将会被缓存!--> <keep-alive> <component v-bind:is="currentTabComponent"></component> </keep-alive> |
2.v-model→ 還需再多看看
Custom events can also be used to create custom inputs that work with
3.<slot></slot>→
v-model
. 3.<slot></slot>→
vue.component在HTML中再寫入任何any template code, including HTML,則需要在組成時的template中寫上 <slot></slot>,否則If
<navigation-link>
did not contain a <slot>
element, any content passed to it would simply be discarded.
→當內容很多時,需要多個slot,可搭配name指定slot
template:`
<div class="container"> <header> <slot name="header"></slot> </header> <main> <slot></slot> </main> <footer> <slot name="footer"></slot> </footer> </div>
`
可以有兩種寫法,一種<template>:
<base-layout> <template slot="header"> <h1>Here might be a page title</h1> </template> <p>A paragraph for the main content.</p> <p>And another one.</p> <template slot="footer"> <p>Here's some contact info</p> </template> </base-layout>
另一種直接寫在元素上
<base-layout> <h1 slot="header">Here might be a page title</h1> <p>A paragraph for the main content.</p> <p>And another one.</p> <p slot="footer">Here's some contact info</p> </base-layout>
→為<slot></slot>提供默認內容:
<button type="submit"> <slot>Submit</slot> </button>
如果父組件為其提供了其他內容,則默認內容就會被替換掉。
→当你想在插槽内使用数据时,例如:
<navigation-link url="/profile"> Logged in as {{ user.name }} </navigation-link> |
该插槽可以访问跟这个模板的其它地方相同的实例属性 (也就是说“作用域”是相同的)。但这个插槽不能访问
<navigation-link>
的作用域。例如尝试访问 url
是不会工作的。牢记一条准则:父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子级作用域内编译。
P.S.
P.S. 直接在 DOM (即非字符串的模板) 中使用时只有 kebab-case 是有效的。
Vue.component
定义全局组件P.S. 直接在 DOM (即非字符串的模板) 中使用时只有 kebab-case 是有效的。
第一章done結束
補充;javascript this應用
A.借用函式
var x = 10; var obj = { x: 20, f: function(){ console.log(this.x); } }; obj.f(); // (1)var fOut = obj.f; fOut(); //(2)var obj2 = { x: 30, f: obj.f } obj2.f(); // (3)
(1)輸出的會是20;而(2)fOut()裡的this,則是因為調用時前方無物件,則this所指的是全域物件,輸出的會是10;最後(3)輸出的會是30。
2.利用call或apply指派this給新物件
call與apply都是呼叫該函式並讓該函式的this指向給予call或apply的第一個參數。至於call和apply的差別則是在於其後面給予被調用之函式的參數放入的方法不同,一個是直接攤平放在第二個以後的參數;一個是直接放入一個裡面放要給予之參數的陣列。
公式:
(A物件.)函式.call(B物件,參數1,參數2,參數3, ......); //函式的this指向B物件(若B物件為null,則指向全域物件) (A物件.)函式.apply(B物件,[參數1,參數2,參數3, ......]); //函式的this指向B物件(若B物件為null,則指向全域物件)
例子:
var obj = {
x: 20;
f: function(){ console.log(this.x); }
};
var obj2 = {
x: 30;
};
obj1.f.call(obj2); //利用call指派f的this為指向obj2,故輸出為30
2.5
如果函式原本具有參數,則可接續在第一個參數之後
→call
function add(num1, num2) {
return
this
.num + num1 + num2;
}
var o = {num :
10
};
console.log(add.call(o,
20
,
30
));
// 60
→apply
function add(num1, num2) {
return this.num + num1 + num2;
}
var o1 = {num : 10};
var o2 = {num : 100};
var args = [20, 30];
console.log(add.apply(o1, args)); // 60
console.log(add.apply(o2, args)); // 150
function toString() {
return this.name;
}
var p1 = {
name : 'Justin',
toString : toString
};
var p2 = {
name : 'momor',
toString : toString
};
console.log(p1.toString()); // Justin
console.log(p2.toString()); // momor
console.log(p1.toString.call(p2)); // momor
3. this指向new所產生之新物件
補充:
var foo = function() {
console.log(this);
}
foo();
new foo();
console.log(this);
}
foo();
new foo();
比较一下 foo() 和 new foo() 的运行结果,你会发现,前者 this 指向的并非 foo 本身,而是当前页面的window对象,而后者才真正的指向foo。
牵涉到“闭包",因为闭包的存在,JavaScript中的作用域变得相当重要。
foo() 函数是在全局作用域(这里就是window对象),所以this的值是当前的window对象。而通过 new foo() 这样的形式,其实是创建了一个foo()的副本,并在这个副本上进行的操作,所以这里的this就是foo()的这个副本。
→创建函数副本
<input type="button" id="aButton" value="demo" />
<script type="text/javascript">
var button = document.getElementById("aButton");
function demo() {
this.value = Math.random();
}
button.onclick= demo;
alert(button.onclick);
</script>
( 输出 )
function demo() {
this.value = Math.random();
}
→函数引用
<input type="button" id="aButton" value="demo" onclick="demo()" />
<script type="text/javascript">
var button = document.getElementById("aButton");
function demo() {
this.value = Math.random();
}
alert(button.onclick);
</script>
( 输出 )
function onclick() {
demo();
}
onclick事件只是直接调用demo()函数,而demo()函数的作用域仍旧是window对象
結論
既然函数副本这么好用,为什么还需要函数引用的方法呢?答案是性能。每新建一个函数的副本,程序就会为这个函数副本分配一定的内存。而实际应用中,大多数函数并不一定会被调用,于是这部分内存就被白白浪费了。而使用函数引用的方式,程序就只会给函数的本体分配内存,而引用只分配指针,这样效率就高很多。
不想用new,卻又想讓this指向元素,該怎麼辦呢?答案是下面程式
<script type="text/javascript">
function demo(obj) {
obj.value = Math.random();
}
</script>
<input type="button" value="demo" onclick="demo(this)" />
<input type="button" value="demo" onclick="demo(this)" />
<input type="button" value="demo" onclick="demo(this)" />
( 這樣效率和需求就都能兼顾 )
用google找一夏this的new用法解析,為什麼作用域指向元素?
更多javascript this請見
https://software.intel.com/zh-cn/blogs/2013/10/09/javascript-this
http://www.cnblogs.com/ruxpinsp1/archive/2008/04/20/1162463.html
vue全部看完後再看https://segmentfault.com/q/1010000008901129,了解KEY的作用(連結裡還連到track-by)
重要: GitHub 仓库的
/dist
文件夹只有在新版本发布时才会提交。如果想要使用 GitHub 上 Vue 最新的源码,你需要自己构建!延伸:
JSX (JavaScript eXtension) is an extension to the JavaScript language syntax. Similar in appearance to HTML.
我们推荐在 React 中使用 JSX 来描述用户界面。JSX 乍看起来可能比较像是模版语言,但事实上它完全是在 JavaScript 内部实现的。
它將HTML寫在JAX裡,避免了XXS(注入攻擊),又
|
|
解析完後:
|
|
git clone https://github.com/vuejs/vue.git node_modules/vue cd node_modules/vue npm install npm run build |
※Google Chrome Apps 環境,会强制应用内容安全策略 (CSP, Content Security Policy ),不能使用
new Function()
对表达式求值。但当通过 webpack + vue-loader 或者 Browserify + vueify 构建时,模板将被预编译为 render
函数,如此便可以在 CSP 环境中完美运行。※
CSP的分类
(1)Content-Security-Policy
配置好并启用后,不符合 CSP 的外部资源就会被阻止加载。
(2)Content-Security-Policy-Report-Only
表示不执行限制选项,只是记录违反限制的行为。它必须与report-uri选项配合使用。
thanks for this usefull article, waiting for this article like this again.
回覆刪除btcu fork