目錄javascript
首發日期:2019-01-19html
有時候,一個後端開發者「不得不」本身去搭建前端界面。若是有的選,固然選一個比較好學的前端「框架」咯(框架不少時候封裝了普通的html元素,使得能更加方便地使用)。
若是你作的項目的界面是一個偏後臺管理的並且要求並不高的界面的時候,你能夠考慮easy UI這個較爲知名的前端框架。
若是你想要界面變得好看一些(easy UI的界面太簡單了,缺少較強的定製性),那麼你能夠考慮vue這個框架。vue這個框架自己並無多少好看的樣式,但學習了這個框架就能夠學會怎麼使用它的第三方組件庫了(這些第三庫看起來都還行)。前端
【Vue本身有官方教程,爲何寫這個呢?主要是感受本身的前端知識不太穩固,看教程的時候有點迷糊。推己及人,因此有了這個博文】vue
例以下面的代碼能夠快速構建一個表格:java
<template> <el-table :data="tableData" style="width: 100%"> <el-table-column prop="date" label="日期" width="180"></el-table-column> <el-table-column prop="name" label="姓名" width="180"></el-table-column> <el-table-column prop="address" label="地址"> </el-table-column> </el-table> </template> <script> export default { data() { return { tableData: [{ date: '2016-05-02', name: '王小虎', address: '上海市普陀區金沙江路 1518 弄' }, { date: '2016-05-04', name: '王小虎', address: '上海市普陀區金沙江路 1517 弄' }, { date: '2016-05-01', name: '王小虎', address: '上海市普陀區金沙江路 1519 弄' }, { date: '2016-05-03', name: '王小虎', address: '上海市普陀區金沙江路 1516 弄' }] } } } </script>
Vue不支持IE8 及如下版本,由於 Vue 使用了 IE8 沒法模擬的 ECMAScript 5 特性。但它支持全部兼容 ECMAScript 5 的瀏覽器。【因此若是項目兼容性要求較高,那麼不適合使用Vue】jquery
【若是你瞭解ORM模型,你應該很能體會到MVVM模型的好處,有了VM層幫咱們管理了數據,咱們就只須要處理好Model層了,這就好像ORM中定義了數據映射關係,而後咱們只須要操做實體類。】webpack
【要想使用Vue,必須先導入/安裝,就像使用jquery必須導入jquery.js同樣;而vue可使用webpack來構建,因此也可使用webpack安裝Vue,但若是你是初學者,先掌握靜態導入的方法吧】ios
Vue的本質也是javascript,因此它也能夠經過導入js文件來使用功能(js能夠用cdn的,也能夠手動導入本地的vue.js)。
這種也是最簡單的使用vue的方式,因此咱們能夠這種方式來做爲入門學習,但正式使用時都會使用webpack來構建vue項目。es6
在html文件中使用以下代碼:【這裏先講導入,後面講使用】web
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script>
npm install vue
npm install --global vue-cli
vue init webpack 項目名
在入門部分將使用js導入方式的例子,在涉及構建多個組件的時候(頁面須要多個組件時,若是把多個組件定義在一個文件中會顯得贅餘。這比如把多個類放到同一個文件中定義。)將使用npm安裝方式演示。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <!--2.這是被vue實例管理的區域--> <div id="app"> {{ message }} </div> </body> <!--1.導入js--> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> //3. 建立實例:new Vue()裏面有一個{}類型的參數,屬性el是一個元素的id名,表明被vue實例管理的區域; var app = new Vue({ el: '#app', data: { message: 'Hello Vue!' } }) </script> </html>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
el: '#app'
表明把id爲app的區域交給vue管理)。那麼對應元素區域裏面就可使用vue的語法了。導入了js以後,vue把管理的區域裏面的vue語法都解析了,因此 {{ message }}就取出了vue實例中名叫message的數據。
如今咱們瞭解了一些vue的渲染頁面的知識,下面咱們來了解更多的渲染技巧。
每一個 Vue 應用都是經過使用 Vue 函數建立一個新的 Vue 實例開始的。
實例中的定義的內容就是咱們可使用在Vue應用中的內容。
下面講實例中能夠定義哪些內容。
var app = new Vue({ el: '#app', data: { message: 'Hello Vue!' } }) //<div id="app"> // {{ message }} //</div>
<body> <div id="app"> <!-- 觸發事件,建議使用Vue的語法來綁定事件(@事件類型,表明綁定什麼事件) --> <!-- 實例內定義的函數,使用Vue的語法來綁定;實例外定義的,可使用原生的方式綁定事件 --> <button @click="myFunction">按鈕</button> </div> </body> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> var app = new Vue({ el: '#app', data: { message: 'Hello Vue!' }, methods: { myFunction: function () { alert('haha') } } }) </script>
【要結合圖來看(懂英文是多麼地好)】
【若是你對生命週期鉤子感興趣,能夠自查,這裏很少講,後面以後根據開發需求來說一些】
測試代碼:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <div id="app"> <button @click='updateValue'>點擊觸發beforeUpdate,updated</button> <button onclick='deleteApp()'>點擊觸發beforeDestory,destoryed</button> <p ref='a'>{{ msg }}</p> </div> </body> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> var app = new Vue({ el: '#app', data: { msg: 'hello' }, beforeCreate: function(){ console.log('beforeCreate') }, created: function(){ console.log('created') }, beforeMount: function(){ console.log(this.$refs.a) // 上面的你會看到undefined,由於數據還沒綁定上 console.log('beforeMount') }, mounted: function(){ console.log(this.$refs.a) // 上面的你會看到p,由於數據綁定上了 console.log('mounted') }, beforeUpdate: function(){ console.log('beforeUpdate') }, updated: function(){ console.log('updated') }, beforeDestroy: function(){ console.log('beforeDestory') }, destroyed: function(){ console.log('destoryed') }, methods: { updateValue: function () { this.msg = 'haha' } } }) function deleteApp() { app.$destroy() } </script> </html>
在上面已經演示了使用Mustache表達式(能夠俗稱插值表達式){{ }}
來獲取實例中的數據了,其實還可使用其餘方式來輸出數據
v-text能夠向元素中輸出文本內容
<div id="app"> <span v-text="message"></span> <!-- message: 'Hello Vue!' --> <!-- var app = new Vue({ el: '#app', data: { message: 'Hello Vue!' } }) --> </div>
v-html能夠向元素中輸出html內容:
<div id="app"> <span v-html="message"></span> <!-- message: 'Hello Vue!'(帶標題樣式的) --> </div> <!-- var app = new Vue({ el: '#app', data: { message: '<h1>Hello Vue!</h1>' } }) -->
Mustache 語法不能做用在 HTML 特性上,也就是說在html元素中沒有 id="{{ id }}" 這樣的操做 ,這種時候須要使用vue語法:v-bind:id="id"
{{ }}裏面可使用javascript表達式,例如:{{ message.split('').reverse().join('') }}
v-bind用於給元素的屬性綁定值
<div id="app"> <span v-bind:title="message">懸浮幾秒,查看標題</span> </div> <!-- var app = new Vue({ el: '#app', data: { message: 'Hello Vue!' } }) -->
<!-- 完整語法 --> <a v-bind:href="url">...</a> <!-- 縮寫 --> <a :href="url">...</a>
v-bind的參數能夠是一個對象,是一個對象時,會把對象的全部屬性都綁定到元素上。具體以下圖。
<div id="app"> <p v-if="seen">如今你看到我了</p> <!-- seen: true 時渲染,seen: false時不渲染 --> </div> <!-- var app = new Vue({ el: '#app', data: { seen: false } }) -->
<div id="app"> <h1 v-if="gender === '男'">男</h1> <h1 v-else-if="gender === '女'">女</h1> <h1 v-else>unknown</h1> </div> <!-- var app = new Vue({ el: '#app', data: { gender: '女' }, }) -->
使用v-else 的元素必須緊跟在帶 v-if 或者 v-else-if 的元素的後面,不然它將不會被識別。
<div id="app"> <h1 v-show="ok">Hello!</h1> </div> <!-- var app = new Vue({ el: '#app', data: { ok: true }, }) -->
<div id="app"> <ol> <!-- 每一次迭代了出數據給todo,都會有一個li元素,並會在li元素中輸出todo的text --> <li v-for="todo in todos"> {{ todo.text }} </li> </ol> </div> <!-- var app = new Vue({ el: '#app', data: { todos: [ { text: '學習 JavaScript' }, { text: '學習 Vue' }, { text: '搞事情' } ] } }) -->
代碼效果:
在 v-for 塊中,咱們擁有對父做用域屬性的徹底訪問權限。[這是來自官網的話,我以爲有點多餘,感受子元素獲取父元素的數據是很正常的操做。]
v-for 還支持一個可選的第二個參數爲當前項的索引,它會從0開始。用來標識當前迭代的是第幾個元素。
能夠用 of 替代 in 做爲分隔符,由於它是最接近 JavaScript 迭代器的語法:
<div v-for="item of items"></div>
也能夠用 v-for 迭代一個對象的全部屬性,第一個參數是value,第二個可選參數是key,第三個可選參數爲索引
第二個參數爲key
<div v-for="(value, key) in object"> {{ key }}: {{ value }} </div>
第三個參數爲索引:
<div v-for="(value, key, index) in object"> {{ index }}. {{ key }}: {{ value }} </div>
使用三個參數時的代碼效果:
在遍歷對象時,是按 Object.keys() 的結果遍歷,可是不能保證它的結果在不一樣的 JavaScript 引擎下是一致的。
v-for 也能夠取一個整數做爲源數據(v-for="i in 10"
)。在這種狀況下,它將重複屢次模板。
當 v-if 與 v-for 一塊兒使用時,v-for 具備比 v-if 更高的優先級。【這個問題官網提了一下,這裏我也提一下,注意使用】
<div id="app"> <p>原消息: "{{ message }}"</p> <p>逆反後: "{{ reversedMessage }}"</p> </div> <!-- var app = new Vue({ el: '#app', data: { message: 'Hello' }, computed: { // 計算屬性的 getter reversedMessage: function () { // `this` 指向 vm 實例 return this.message.split('').reverse().join('') } } }) -->
下面的代碼也能夠達到上面的效果
(也是即時的,有人不懂爲何這個函數會重複調用,而非頁面初始化時調用一次;由於當頁面中數據更新的時候,涉及頁面數據的函數也會從新執行。)
<div id="app"> <p>原消息: "{{ message }}"</p> <p>逆反後: "{{ reversedMessage() }}"</p> <p>{{ Date.now() }}"</p> <!-- 後面的now是用來測試數據刷新時,函數會從新執行 --> </div> <!-- var app = new Vue({ el: '#app', data: { message: 'Hello' }, methods: { reversedMessage: function () { // `this` 指向 vm 實例 return this.message.split('').reverse().join('') } } }) -->
函數也能夠達到一樣的效果,可是函數沒有緩存效果,而計算屬性有緩存。沒有緩存時,函數每一次都要從新計算來獲得結果,若是這是一個比較消耗資源的計算的話,那麼會減慢頁面的速度;而計算屬性有緩存,只要內部的計算元素沒有發生變化,那麼會使用緩存來做爲計算結果。
上面的計算屬性達到效果須要留意計算元素的變化,你可能會想到一些相似的監聽數據變化的方法,而vue中也是有這樣的東西的。
下面的代碼監聽了firstName和lastName,當這兩個數據變化的時候會從新給fullName賦值。
<div id="app"> <div>{{ fullName }}</div> </div> <!-- var app = new Vue({ el: '#app', data: { firstName: 'Foo', lastName: 'Bar', fullName: 'Foo Bar' }, watch: { firstName: function (val) { this.fullName = val + ' ' + this.lastName }, lastName: function (val) { this.fullName = this.firstName + ' ' + val } } }) -->
使用計算屬性達到上面效果(顯然省了很多代碼):
var vm = new Vue({ el: '#demo', data: { firstName: 'Foo', lastName: 'Bar' }, computed: { fullName: function () { return this.firstName + ' ' + this.lastName } } })
<div id="app"> <div>{{ fullName }}</div> </div> <!-- var app = new Vue({ el: '#app', 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] } } } }) -->
雖然計算屬性已經提供了不少的好處,但有些時候計算屬性也不能知足咱們的要求。好比咱們但願監聽某個屬性的變化來獲得另外一個屬性的結果,可是不但願它立刻獲得結果,那麼這時候計算屬性就達不到需求了。而監聽器裏面能夠寫一些其餘代碼(好比一些延遲去獲得結果的代碼)。
當須要在數據變化時執行異步或開銷較大的操做時,watch是最有用的。
爲何有時候不但願計算新結果那麼快呢?這就比如有人在百度搜索中輸入一個個字,若是每一個字都要進行檢索的話,那麼就對百度來講開銷就很大了,若是稍微等等,確認用戶輸入完畢再去計算,那麼就節省了不少資源了,下面的來自官網的例子正是一種這樣的考慮了資源開銷的例子。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <div id="watch-example"> <p> Ask a yes/no question: <input v-model="question"> </p> <p>{{ answer }}</p> </div> </body> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <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> </html>