實現數據的請求css
then指定成功回調html
真正的數據是在result.body中放着前端
除了 vue-resource 以外,還可使用 axios 的第三方包實現實現數據的請求vue
axios是一個基於promise的HTTP庫,能夠用在瀏覽器和node.js中node
請求地址webpack
get請求地址: http://vue.studyit.io/api/getlunboios
post請求地址:http://vue.studyit.io/api/postweb
jsonp請求地址:http://vue.studyit.io/api/jsonpvue-router
JSONP的實現原理sql
因爲瀏覽器的安全性限制,不容許AJAX訪問 協議不一樣、域名不一樣、端口號不一樣的 數據接口,瀏覽器認爲這種訪問不安全。
能夠經過動態建立script標籤的形式,把script標籤的src屬性,指向數據接口的地址,由於script標籤不存在跨域限制,這種數據獲取方式,稱做JSONP
具體實現過程:
先在客戶端定義一個回調方法,預約義對數據的操做
再把這個回調方法的名稱,經過URL傳參的形式,提交到服務器的數據接口
服務器數據接口組織好要發送給客戶端的數據,再拿着客戶端傳遞過來的回調方法名稱,拼接出一個調用這個方法的字符串,發送給客戶端去解析執行
客戶端拿到服務器返回的字符串以後,看成Script腳本去解析執行,這樣就可以拿到JSONP的數據了
實例
const http = require('http'); // 導入解析 URL 地址的核心模塊 const urlModule = require('url'); const server = http.createServer(); // 監聽 服務器的 request 請求事件,處理每一個請求 server.on('request', (req, res) => { const url = req.url; // 解析客戶端請求的URL地址,截取parse部分,true表示用query的方法 var info = urlModule.parse(url, true); // 若是請求的 URL 地址是 /getjsonp ,則表示要獲取JSONP類型的數據 if (info.pathname === '/getjsonp') { // 獲取客戶端指定的回調函數的名稱 var cbName = info.query.callback; // 手動拼接要返回給客戶端的數據對象 var data = { name: 'zs', age: 22, gender: '男', hobby: ['吃飯', '睡覺', '運動'] } // 拼接出一個方法的調用,在調用這個方法的時候,把要發送給客戶端的數據,序列化爲字符串,做爲參數傳遞給這個調用的方法: var result = `${cbName}(${JSON.stringify(data)})`; // 將拼接好的方法的調用,返回給客戶端去解析執行 res.end(result); } else { res.end('404'); } }); server.listen(3000, () => { console.log('server running at http://127.0.0.1:3000'); });
直接在頁面中,經過script標籤,引入 vue-resource 的腳本文件
引用的前後順序是:先引用 Vue 的腳本文件,再引用 vue-resource 的腳本文件
get一個參數,要請求的URL地址
post三個參數
參數一,要請求的URL地址
參數二,要發送的數據對象
參數三,指定post提交的編碼類型爲application/x-www-form-urlencoded
jsonp一個參數,要請求的URL地址
then後面是成功以後的函數
//發送get getInfo() { // get 方式獲取數據 this.$http.get('http://127.0.0.1:8899/api/getlunbo').then(res => { console.log(res.body); }) } //發送post postInfo() { //將post發送請求的第一個參數提取出來 var url = 'http://127.0.0.1:8899/api/post'; //要發送的數據是 name:'zs' //指定post提交編碼的類型爲application/x-www-form-urlencoded this.$http.post(url, { name: 'zs' }, { emulateJSON: true }).then(res => { console.log(res.body); }); } //發送jsonp jsonpInfo() { // JSONP形式從服務器獲取數據 var url = 'http://127.0.0.1:8899/api/jsonp'; this.$http.jsonp(url).then(res => { console.log(res.body); }); }
地址中若是有相同的根路徑,能夠提取出來
請求中,url前面有斜槓的時候,不啓用根路徑的設置,沒有斜槓的時候,啓用根路徑拼接
Vue.http.options.root='http://vue.studyit.io' //api前面沒有斜槓,表示要和前面抽離的根路徑部分進行拼接,造成完整的路徑 this.$http.get('api/getprodlist').then(result=>{//功能})
和根路徑相似的,post中的第三個參數也能夠提取出來,進行全局配置
指定post提交的編碼類型爲application/x-www-form-urlencoded
Vue.http.options.emulateJSON=true;
先解壓安裝 PHPStudy;
解壓安裝 Navicat 這個數據庫可視化工具,並激活;
打開 Navicat 工具,新建空白數據庫,名爲 dtcmsdb4;
雙擊新建的數據庫,鏈接上這個空白數據庫,在新建的數據庫上右鍵 -> 運行SQL文件,選擇並執行dtcmsdb4.sql 這個數據庫腳本文件;若是執行不報錯,則數據庫導入完成;
進入文件夾 vuecms3_nodejsapi 內部,執行 npm i 安裝全部的依賴項;
先確保本機安裝了 nodemon, 沒有安裝,則運行 npm i nodemon -g 進行全局安裝,安裝完畢後,進入到 vuecms3_nodejsapi目錄 -> src目錄 -> 雙擊運行 start.bat
若是API啓動失敗,請檢查 PHPStudy 是否正常開啓,同時,檢查 app.js 中第 14行 中數據庫鏈接配置字符串是否正確;PHPStudy 中默認的 用戶名是root,默認的密碼也是root
動畫的一個過程包括四個時間點和兩個時間段
使用transition元素把須要被動畫控制的元素包裹起來
transition是Vue官方提供的
Vue把一個完整的動畫,使用鉤子函數,拆分爲了兩部分
使用flag標識符來表示動畫的切換
兩組:v-enter,v-leave-to和v-enter-active,v-leave-active
style標籤中設置兩組樣式
v-enter 時間點,進入以前,元素的起始狀態,此時尚未開始進入
v-leave-to 動畫離開以後,離開的終止狀態,此時,元素動畫已經結束
v-enter-active 入場動畫的時間段
v-leave-active 出場動畫的時間段
區分不一樣組之間的動畫,在transition上加一個name
能夠利用:duration="毫秒值" 來統一設置時間
<!-- 用兩組樣式來呈現動畫效果 --> <style> .v-enter, .v-leave-to { opacity: 0; transform: translateX(150px); } .v-enter-active, .v-leave-active{ transition: all 0.8s ease; } </style> </head> <body> <div id="app"> <!-- 點擊事件,flag等於flag取反,也就是點擊就取反,呈現切換效果 --> <input type="button" value="toggle" @click="flag=!flag"> <transition> <h3 v-if="flag">這是一個H3</h3> </transition> </div> <script> // 建立 Vue 實例,獲得 ViewModel var vm = new Vue({ el: '#app', data: { //flag初始值設定爲false flag: false }, methods: {} }); </script> </body> </html> ----------------動畫部分能夠添加name屬性,這樣類樣式也要跟着改變,將前綴改爲name的值 <transition name="my"> <h6 v-if="flag2">這是一個H6</h6> </transition> <style> .my-enter, .my-leave-to { opacity: 0; transform: translateY(70px); } .my-enter-active, .my-leave-active{ transition: all 0.8s ease; } </style>
transition中enter-active-class="bounceIn"和leave-active-class="bounceOut"屬於第三方類,能夠用來設置特殊的效果
:duration="{ enter: 200, leave: 400 }"能夠分開設置時間
除了效果的類名,還須要加animated類,這個類能夠加到transition上也能夠加到元素上
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <script src="./lib/vue-2.4.0.js"></script> <!-- 須要引入樣式的包 --> <link rel="stylesheet" href="./lib/animate.css"> <!-- 入場 bounceIn 離場 bounceOut --> </head> <body> <div id="app"> <!-- 點擊切換 --> <input type="button" value="toggle" @click="flag=!flag"> <!-- 進入的類名 enter-active-class --> <!-- 離開的類名 leave-active-class --> <!-- <transition enter-active-class="bounceIn" leave-active-class="bounceOut" :duration="200"> <h3 v-if="flag" class="animated">這是一個H3</h3> </transition> --> <!-- 使用 :duration="{ enter: 200, leave: 400 }" 來分別設置 入場的時長 和 離場的時長 --> <transition enter-active-class="bounceIn" leave-active-class="bounceOut" :duration="{ enter: 200, leave: 400 }"> <!-- 要加上animated的類名,能夠加在transition上,也能夠直接加在元素上 --> <h3 v-if="flag" class="animated">這是一個H3</h3> </transition> </div> <script> // 建立 Vue 實例,獲得 ViewModel var vm = new Vue({ el: '#app', data: { flag: false }, methods: {} }); </script> </body> </html>
使用transition把元素包裹起來
Vue把一個完整的動畫,使用鉤子函數,拆分爲了兩部分
動畫鉤子函數的第一個參數:el,表示要執行動畫的那個DOM元素,是個原生的 JS DOM對象,在下面的例子中,el就是小球
el 是經過document.getElementById('') 方式獲取到的原生JS DOM對象
beforeEnter 表示動畫入場以前動畫還沒有開始,能夠在beforeEnter 中,設置元素開始動畫以前的起始樣式
enter 表示動畫開始以後的樣式,能夠設置小球完成動畫以後的,結束狀態
enter中el.offsetWidth這句話沒有實際的做用,可是若是不寫會報錯
能夠認爲 el.offsetWidth 會強制動畫刷新,這裏的Width能夠寫成Height,Left,Right
enter中的第二個參數done,以後在enter函數最後調用了done
這裏的 done, 起始就是 afterEnter 這個函數,也就是說,done 是 afterEnter 函數的引用
下面的例子是半場動畫
再次點擊按鈕的時候 小球瞬間回到00位置,接着執行以前的過程,這就是爲何每次點擊小球都會回到原處的緣由
<style> .ball { width: 15px; height: 15px; border-radius: 50%; background-color: red; } </style> </head> <body> <div id="app"> <input type="button" value="快到碗裏來" @click="flag=!flag"> <!-- 半場動畫 --> <transition @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter"> <div class="ball" v-show="flag"></div> </transition> </div> <script> // 建立 Vue 實例 var vm = new Vue({ el: '#app', data: { flag: false }, methods: { beforeEnter(el){ // 設置小球開始動畫以前的,起始位置 el.style.transform = "translate(0, 0)" }, enter(el, done){ el.offsetWidth el.style.transform = "translate(150px, 450px)" el.style.transition = 'all 1s ease' //這裏調用done就至關於調用afterEnter done() }, afterEnter(el){ // 動畫完成以後,會調用 afterEnter // console.log('ok') this.flag = !this.flag } } }); </script> </body> </html>
v-move和v-leave-active配合使用,可以實現列表後續的元素,漸漸浮上來的效果
列表過渡的時候,不能再用transition包裹,須要用transition-group
爲v-for循環建立的元素設置動畫,必須爲每個元素設置:key屬性
給transition-group添加appear屬性,實現頁面剛展現出來的時候,入場時候的效果
經過爲transition-group設置tag屬性,指定transition-group渲染以後成爲何元素,若是不指定tag屬性,默認渲染span標籤,若是是在ul標籤中默認渲染,ul標籤中除了li還有span,不符合W3C語法標準,因此這裏要把ul標籤去掉,讓transition-group渲染成ul
<style> li { border: 1px dashed #999; margin: 5px; line-height: 35px; padding-left: 5px; font-size: 12px; width: 100%; } li:hover { background-color: hotpink; transition: all 0.8s ease; } .v-enter, .v-leave-to { opacity: 0; transform: translateY(80px); } .v-enter-active, .v-leave-active { transition: all 0.6s ease; } .v-move { transition: all 0.6s ease; } .v-leave-active{ position: absolute; } </style> </head> <body> <div id="app"> <div> <label>Id: <input type="text" v-model="id"> </label> <label>Name: <input type="text" v-model="name"> </label> <input type="button" value="添加" @click="add"> </div> <!-- <ul> --> <transition-group appear tag="ul"> <li v-for="(item, i) in list" :key="item.id" @click="del(i)"> {{item.id}} --- {{item.name}} </li> </transition-group> <!-- </ul> --> </div> <script> // 建立 Vue 實例,獲得 ViewModel var vm = new Vue({ el: '#app', data: { id: '', name: '', list: [ { id: 1, name: '趙高' }, { id: 2, name: '秦檜' }, { id: 3, name: '嚴嵩' }, { id: 4, name: '魏忠賢' } ] }, methods: { add() { //list中添加元素 this.list.push({ id: this.id, name: this.name }) this.id = this.name = '' }, del(i) { //刪除當前項 this.list.splice(i, 1) } } }); </script> </body> </html>
組件的出現,就是爲了拆分Vue實例的代碼量的,可以讓咱們以不一樣的組件,來劃分不一樣的功能模塊,未來咱們須要什麼樣的功能,就能夠去調用對應的組件便可。
組件化和模塊化的不一樣:
模塊化: 是從代碼邏輯的角度進行劃分的;方便代碼分層開發,保證每一個功能模塊的職能單一
組件化: 是從UI界面的角度進行劃分的;前端的組件化,方便UI組件的重用
Vue實例就是父組件
path設置地址,component設置組件,router-to表示去哪一個路由
第一種
使用Vue.extend來建立全局的Vue組件
使用Vue.component('組件名稱',建立出來的組件模板對象)
template屬性制定了組件要展現的HTML結構
若是使用Vue.component定義全局組件的時候,組件名稱使用了駝峯命名,在引用組件的時候,就要用短橫鏈接的方式。若是沒有使用短橫鏈接,直接寫這個名字就能夠
Vue.component第一個參數是組件名稱,在引用組件的時候,以一個標籤形式引入,第二個參數是Vue.extend建立的組件,其中template就是組件將要展現的HTML內容
<body> <div id="app"> <!-- 若是要使用組件,直接,把組件的名稱,以 HTML 標籤的形式,引入到頁面中,便可 --> <mycom1></mycom1> </div> <script> //建立全局的Vue組件 var com1 = Vue.extend({ template: '<h3>這是使用 Vue.extend 建立的組件</h3>' }) //定義全局組件 Vue.component('mycom1', com1) // 建立 Vue 實例,獲得 ViewModel var vm = new Vue({ el: '#app', data: {}, methods: {} }); </script> </body> </html> ------- //能夠簡寫成下面這種模式,不須要中間變量來接收 <script> Vue.component('mycom1', Vue.extend({ template: '<h3>這是使用 Vue.extend 建立的組件</h3>' })) </script>
第二種
不管哪一種方式建立出來的組件,組件的template屬性指向的模板內容,必須有且只有惟一一個的根元素
若是不加div標籤在最外邊包裹,h3和span並列使用,而且是根元素的位置,這樣會報錯
<body> <div id="app"> <!-- 仍是使用 標籤形式,引入本身的組件 --> <mycom2></mycom2> </div> <script> //這裏省去了extend,直接引用模板 Vue.component('mycom2', { template: '<div><h3>這是直接使用 Vue.component 建立出來的組件</h3><span>123</span></div>' }) // 建立 Vue 實例,獲得 ViewModel var vm = new Vue({ el: '#app', data: {}, methods: {} }); </script> </body>
第三種
在被控制的#app外面,使用template元素,定義組件的HTML模板結構
實例內部添加components對象,能夠定義私有的組件
<body> <div id="app"> <mycom3></mycom3> <!-- <login></login> --> </div> <div id="app2"> <mycom3></mycom3> <login></login> </div> <template id="tmpl"> <div> <h1>這是經過 template 元素,在外部定義的組件結構,這個方式,有代碼的只能提示和高亮</h1> <h4>好用,不錯!</h4> </div> </template> <template id="tmpl2"> <h1>這是私有的 login 組件</h1> </template> <script> //全局的組件 Vue.component('mycom3', { template: '#tmpl' }) // 建立 Vue 實例,獲得 ViewModel var vm = new Vue({ el: '#app', data: {}, methods: {} }); var vm2 = new Vue({ el: '#app2', data: {}, methods: {}, filters: {}, directives: {}, components: { // 定義實例內部私有組件的 login: { template: '#tmpl2' } } }) </script> </body> </html> -------- 若是沒有使用模板,而且是局部私有組件 <script> components: { // 定義實例內部私有組件的 'login':login } //這裏屬性名和值同樣,能夠進一步簡寫 components: { // 定義實例內部私有組件的 login } </script>
組件中能夠有本身的data數據
組件的data和實例的data不同,實例中的data能夠是對象,可是組件中的data必須是一個方法
組件中data的內部必須返回一個對象
組件中data數據使用方式和實例中data使用方式相同
<body> <div id="app"> <mycom1></mycom1> </div> <script> Vue.component('mycom1', { template: '<h1>這是全局組件 --- {{msg}}</h1>', //組件中data必須是方法 data: function () { //data中必須返回一個對象 return { msg: '這是組件的中data定義的數據' } } }) // 建立 Vue 實例,獲得 ViewModel var vm = new Vue({ el: '#app', data: {}, methods: {} }); </script> </body>
爲何data內部必須return一個對象
若是當count的數據在全局定義成一個對象的時候,在data中直接引用,至關因而引用了全局的對象
這個對象是引用類型,一個發生變化,全部的都會發生變化
因此對象須要data內部本身定義
<body> <div id="app"> <counter></counter> <hr> <counter></counter> <hr> <counter></counter> </div> <template id="tmpl"> <div> <input type="button" value="+1" @click="increment"> <h3>{{count}}</h3> </div> </template> <script> var dataObj = { count: 0 } // 這是一個計數器的組件, 身上有個按鈕,每當點擊按鈕,讓 data 中的 count 值 +1 Vue.component('counter', { template: '#tmpl', data: function () { //若是返回dataObj,上面的counter,三個都會是同一個值,由於是引用類型 // return dataObj return { count: 0 } }, methods: { increment() { this.count++ } } }) // 建立 Vue 實例,獲得 ViewModel var vm = new Vue({ el: '#app', data: {}, methods: {} }); </script> </body>
第一種
<body> <div id="app"> <a href="" @click.prevent="flag=true">登陸</a> <a href="" @click.prevent="flag=false">註冊</a> <!-- 這裏的if else 切換特性 --> <login v-if="flag"></login> <register v-else="flag"></register> </div> <script> Vue.component('login', { template: '<h3>登陸組件</h3>' }) Vue.component('register', { template: '<h3>註冊組件</h3>' }) // 建立 Vue 實例,獲得 ViewModel var vm = new Vue({ el: '#app', data: { flag: false }, methods: {} }); </script> </body>
第二種
Vue提供了component元素,展現對應的名稱組件,至關於一個佔位符
冒號is屬性,能夠用來指定要展現的組件的名稱
冒號表示綁定,雙引號中的內容默認不是字符串,因此組件名稱(字符串)放進去的時候要加單引號
能夠在data中定義一個變量,用來承載組件名稱,點擊連接切換這個變量的值就能夠了
組件也能夠用動畫的標籤包裹起來,加一個屬性先出後進
<body> <div id="app"> <!-- 點擊讓組件名稱變成login --> <a href="" @click.prevent="comName='login'">登陸</a> <!-- 點擊讓組件名稱變成register --> <a href="" @click.prevent="comName='register'">註冊</a> <!-- Vue提供了 component ,來展現對應名稱的組件 --> <!-- component 是一個佔位符 --> <!--:is 屬性,能夠用來指定要展現的組件的名稱 --> <component :is="comName"></component> </div> <script> // 組件名稱是 字符串 Vue.component('login', { template: '<h3>登陸組件</h3>' }) Vue.component('register', { template: '<h3>註冊組件</h3>' }) // 建立 Vue 實例,獲得 ViewModel var vm = new Vue({ el: '#app', data: { // 當前 component 中的 :is 綁定的組件的名稱 // 默認是login comName: 'login' }, methods: {} }); </script> </body>
切換動畫
<style> .v-enter, .v-leave-to { opacity: 0; transform: translateX(150px); } .v-enter-active, .v-leave-active { transition: all 0.5s ease; } </style> <body> <div id="app"> <a href="" @click.prevent="comName='login'">登陸</a> <a href="" @click.prevent="comName='register'">註冊</a> <!-- 經過 mode 屬性,設置組件切換時候的 模式 --> <!-- out-in 表示先出後進 --> <transition mode="out-in"> <component :is="comName"></component> </transition> </div> <script> // 組件名稱是 字符串 Vue.component('login', { template: '<h3>登陸組件</h3>' }) Vue.component('register', { template: '<h3>註冊組件</h3>' }) // 建立 Vue 實例,獲得 ViewModel var vm = new Vue({ el: '#app', data: { comName: 'login' // 當前 component 中的 :is 綁定的組件的名稱 }, methods: {} }); </script> </body>
父組件,能夠在引用子組件的時候, 經過屬性綁定(v-bind:)的形式,把須要傳遞給子組件的數據,以屬性綁定的形式,傳遞到子組件內部,供子組件使用
子組件若是想使用這個屬性須要在本身內部用props定義一下
這裏的props是一個數組,裏面放字符串格式的屬性名就能夠了
子組件中,默認沒法訪問到父組件中的data上的數據和methods中的方法
子組件中的data 數據,並非經過 父組件傳遞過來的,而是子組件自身私有的,子組件經過 Ajax ,請求回來的數據,均可以放到 data 身上
data 上的數據,都是可讀可寫的。props 中的數據,都是隻讀的,沒法從新賦值
<body> <div id="app"> <!-- 父組件 屬性綁定msg --> <com1 v-bind:parentmsg="msg"></com1> </div> <script> // 建立 Vue 實例,獲得 ViewModel var vm = new Vue({ el: '#app', data: { msg: '123 父組件中的數據' }, methods: {}, components: { //子組件 com1: { //子組件中data是一個function,return的是一個對象 data() { return { title: '123', content: 'qqq' } }, //子組件中定義模板 template: '<h1 @click="change">這是子組件---{{parentmsg}}</h1>', //子組件的props定義父組件中的屬性 props: ['parentmsg'], methods: { change() { this.parentmsg = '被修改了' } } }, } }); </script> </body>
父組件向子組件傳遞方法,使用的是事件綁定機制
v-on當咱們自定義了一個事件屬性以後,子組件就可以,經過某些方式,來調用傳遞進去的這個方法了
show不帶括號,表示直接將方法引用給了func
若是有括號,表示將show的return結果給func
emit表明觸發的意思
點擊組件上的按鈕就能調用父組件上的方法
若是父組件中的方法有參數,在子組件中引用的時候,從第二個參數開始就能夠傳遞參數
<body> <div id="app"> <!-- 父組件中綁定事件 --> <!-- show不帶括號,表示直接將引用給了func --> <!-- show帶括號的時候表示將show中的return給func --> <com2 @func="show"></com2> </div> <template id="tmpl"> <div> <h1>這是子組件</h1> <input type="button" value="子組件按鈕,點擊觸發父組件傳過來的方法" @click="myclick"> </div> </template> <script> var com2 = { template: '#tmpl', data() { return { sonmsg: { name: '小頭兒子', age: 8 } } }, methods: { myclick() { this.$emit('func', this.sonmsg) } } } // 建立 Vue 實例,獲得 ViewModel var vm = new Vue({ el: '#app', data: { datamsgFormSon: null }, methods: { show(data) { this.datamsgFormSon = data console.log('調用了父組件身上的 show 方法: --- ' + data) } }, components: { com2 } }); </script> </body>
父組件將方法的引用,傳遞到子組件內部,子組件在內部調用父組件傳遞過來的方法,同時把要發送給父組件的數據,在調用方法的時候看成參數傳遞進去
父組件將方法的引用傳遞給子組件,其中,getMsg是父組件中methods中定義的方法名稱,func是子組件調用傳遞過來方法時候的方法名稱
<son @func="getMsg"></son>
子組件內部經過this.$emit('方法名', 要傳遞的數據)方式,來調用父組件中的方法,同時把數據傳遞給父組件使用
<div id="app"> <!-- 引用父組件 --> <son @func="getMsg"></son> <!-- 組件模板定義 --> <script type="x-template" id="son"> <div> <input type="button" value="向父組件傳值" @click="sendMsg" /> </div> </script> </div> <script> // 子組件的定義方式 Vue.component('son', { template: '#son', // 組件模板Id methods: { sendMsg() { // 按鈕的點擊事件 this.$emit('func', 'OK'); // 調用父組件傳遞過來的方法,同時把數據傳遞出去 } } }); // 建立 Vue 實例,獲得 ViewModel var vm = new Vue({ el: '#app', data: {}, methods: { getMsg(val){ // 子組件中,經過 this.$emit() 實際調用的方法,在此進行定義 alert(val); } } }); </script>
能夠經過ref獲取元素,reference引用的意思
h3就是單個的元素ref,不須要帶s,可是vm上的$refs能夠有多個引用,因此帶s
經過$refs能夠拿到組件的引用,能夠直接用組件中的數據和方法
<body> <div id="app"> <input type="button" value="獲取元素" @click="getElement" ref="mybtn"> <!-- 這裏的h3是單個元素,ref不須要加s --> <h3 id="myh3" ref="myh3">哈哈哈哈</h3> <hr> <login ref="mylogin"></login> </div> <script> var login={ template:'<h1>登錄組件</h1>', data(){ return{ msg:'son msg' } }, methods:{ show(){ console.log('調用了子組件的方法'); } } } // 建立 Vue 實例,獲得 ViewModel var vm = new Vue({ el: '#app', data: {}, methods: { getElement(){ console.log(this.$refs.mylogin.msg); } }, components: { //這裏將login抽離出去進行定義了 login } }); </script> </body>
後端路由:對於普通的網站,全部的超連接都是URL地址,全部的URL地址都對應服務器上對應的資源。
前端路由:對於單頁面應用程序來講,主要經過URL中的hash(#號)來實現不一樣頁面之間的切換,同時,hash有一個特色:HTTP請求中不會包含hash相關的內容;因此,單頁面程序中的頁面跳轉主要用hash實現。
在單頁面應用程序中,這種經過hash改變來切換頁面的方式,稱做前端路由(區別於後端路由)。
導入router的包
使用router-link組件來導航
使用router-view 組件來顯示匹配到的組件,至關於佔位符
建立一個路由router 實例,經過routes屬性來定義路由匹配規則,注意這裏是routes不是router
使用router屬性來使用路由規則
router經過vm實例的一個屬性和vm關聯起來
其中router-link的地方能夠用a標籤實現跳轉,可是使用hash每次都要加#,<a href="#/login">登陸</a>,這麼寫比較麻煩,因此採用router-link的寫法
router-link會默認渲染成一個a標籤,裏面添加tag屬性,能夠指定渲染成什麼標籤,可是無論渲染成什麼標籤依然有跳轉的功能
redirect是重定向
router中的連接有特殊的類名,給這些類名添加樣式就能夠控制連接的高亮效果
特殊類名是router-link-active,是默認的,可使用linkActiveClass更改爲簡單的名字
將路由規則對象,註冊到vm實例上,用來監聽url地址的變化,而後展現對應的組件
<body> <div id="app"> <router-link to="/login" tag="span">登陸</router-link> <router-link to="/register">註冊</router-link> <transition> <router-view></router-view> </transition> </div> <script> var login = { template: '<h1>登陸組件</h1>' } var register = { template: '<h1>註冊組件</h1>' } //建立路由對象 var routerObj = new VueRouter({ //routes分發路由 routes: [ //redirect重定向,根路徑的時候,重定向到login頁面 {path: '/',redirect: '/login'}, {path: '/login',component: login}, {path: '/register',component: register} ], //將複雜的路由類名改爲本身定義的類名 linkActiveClass: 'myactive' }) // 建立 Vue 實例,獲得 ViewModel var vm = new Vue({ el: '#app', data: {}, methods: {}, //用來監聽url地址變化 router: routerObj }); </script> </body>
若是在路由中,使用查詢字符串,給路由傳遞參數,則不須要修改 路由規則的path屬性
能夠直接在模板中渲染這個參數
用query獲取參數
<body> <div id="app"> <!-- 查詢字符串的形式 --> <router-link to="/login?id=10&name=zs">登陸</router-link> <router-link to="/register">註冊</router-link> <router-view></router-view> </div> <script> var login = { template: '<h1>登陸-{{$route.query.id}}-{{$route.query.name}}</h1>', data() { return { msg: '123' } }, created() { console.log(this.$route); } } var register = { template: '<h1>註冊</h1>' } var router = new VueRouter({ routes: [{ path: '/login', component: login }, { path: '/register', component: register }, ] }) // 建立 Vue 實例,獲得 ViewModel var vm = new Vue({ el: '#app', data: {}, methods: {}, router }); </script> </body>
可使用另外一種方法
能夠直接從params中獲取參數
params是經過match解析出來的
<body> <div id="app"> <!-- 用斜槓方式進行傳參 --> <router-link to="/login/12/ls">登陸</router-link> <router-link to="/register">註冊</router-link> <router-view></router-view> </div> <script> var login = { template: '<h1>登陸 --- {{ $route.params.id }} --- {{ $route.params.name }}</h1>', data(){ return { msg: '123' } }, created(){ // 組件的生命週期鉤子函數 console.log(this.$route.params.id) } } var register = { template: '<h1>註冊</h1>' } var router = new VueRouter({ routes: [ { path: '/login/:id/:name', component: login }, { path: '/register', component: register } ] }) // 建立 Vue 實例,獲得 ViewModel var vm = new Vue({ el: '#app', data: {}, methods: {}, // router: router router }); </script> </body>
使用children屬性,實現子路由,子路由的 path 前面,不要帶 / ,不然永遠以根路徑開始請求,這樣不方便咱們用戶去理解URL地址
<body> <div id="app"> <router-link to="/account">Account</router-link> <router-view></router-view> </div> <template id="tmpl"> <div> <h1>這是 Account 組件</h1> <router-link to="/account/login">登陸</router-link> <router-link to="/account/register">註冊</router-link> <router-view></router-view> </div> </template> <script> // 組件的模板對象 var account = { template: '#tmpl' } var login = { template: '<h3>登陸</h3>' } var register = { template: '<h3>註冊</h3>' } var router = new VueRouter({ routes: [ { path: '/account', component: account, // children: [ { path: 'login', component: login }, { path: 'register', component: register } ] } ] }) // 建立 Vue 實例,獲得 ViewModel var vm = new Vue({ el: '#app', data: {}, methods: {}, router }); </script> </body>
router-view有name屬性能夠匹配到相應的內容
<body> <div id="app"> <router-view></router-view> <div class="container"> <router-view name="left"></router-view> <router-view name="main"></router-view> </div> </div> <script> var header = { template: '<h1 class="header">Header頭部區域</h1>' } var leftBox = { template: '<h1 class="left">Left側邊欄區域</h1>' } var mainBox = { template: '<h1 class="main">mainBox主體區域</h1>' } // 建立路由對象 var router = new VueRouter({ routes: [ /* { path: '/', component: header }, { path: '/left', component: leftBox }, { path: '/main', component: mainBox } */ { path: '/', components: { 'default': header, 'left': leftBox, 'main': mainBox } } ] }) // 建立 Vue 實例,獲得 ViewModel var vm = new Vue({ el: '#app', data: {}, methods: {}, router }); </script> </body>
文本框綁定鍵盤擡起事件
這種方式能夠監測文本框等能夠綁定事件的元素,但若是想要監測地址欄的內容,用這種綁定方法就不能執行了
<body> <div id="app"> <input type="text" v-model="firstname" @keyup="getFullname"> + <input type="text" v-model="lastname" @keyup="getFullname"> = <input type="text" v-model="fullname"> </div> <script> // 建立 Vue 實例,獲得 ViewModel var vm = new Vue({ el: '#app', data: { firstname: '', lastname: '', fullname: '' }, methods: { getFullname() { this.fullname = this.firstname + '-' + this.lastname } } }); </script> </body>
和methods同級的,有一個watch對象
watch中firstname屬性能夠監視data中指定數據的變化,而後觸發watch中對應的function處理函數
這個函數中能夠監測新值舊值的變化,newVal和oldVal
<body> <div id="app"> <input type="text" v-model="firstname"> + <input type="text" v-model="lastname"> = <input type="text" v-model="fullname"> </div> <script> // 建立 Vue 實例,獲得 ViewModel var vm = new Vue({ el: '#app', data: { firstname: '', lastname: '', fullname: '' }, methods: {}, watch: { // 使用這個 屬性,能夠監視 data 中指定數據的變化, //而後觸發這個 watch 中對應的 function 處理函數 'firstname': function (newVal, oldVal) { console.log('監視到了 firstname 的變化') // this.fullname = this.firstname + '-' + this.lastname // console.log(newVal + ' --- ' + oldVal) this.fullname = newVal + '-' + this.lastname }, 'lastname': function (newVal) { this.fullname = this.firstname + '-' + newVal } } }); </script> </body>
watch監測路由地址的變化
將$route.path傳到watch裏當作屬性
若是newVal是/login代表跳轉到了登陸頁面
若是newVal是/register代表跳轉到了註冊頁面
<body> <div id="app"> <router-link to="/login">登陸</router-link> <router-link to="/register">註冊</router-link> <!-- 容器 --> <router-view></router-view> </div> <script> // 2. 建立子組件 var login = { template: '<h3>這是登陸子組件,這個組件是 奔波霸 開發的。</h3>' } var register = { template: '<h3>這是註冊子組件,這個組件是 霸波奔 開發的。</h3>' } // 3. 建立一個路由對象 var router = new VueRouter({ routes: [ // 路由規則數組 { path: '/', redirect: '/login' }, { path: '/login', component: login }, { path: '/register', component: register } ], linkActiveClass: 'myactive' // 和激活相關的類 }) // 建立 Vue 實例,獲得 ViewModel var vm = new Vue({ el: '#app', data: {}, methods: {}, // router: router router, watch: { // this.$route.path '$route.path': function (newVal, oldVal) { // console.log(newVal + ' --- ' + oldVal) if (newVal === '/login') { console.log('歡迎進入登陸頁面') } else if (newVal === '/register') { console.log('歡迎進入註冊頁面') } } } }); </script> </body>
computed中定義的屬性叫作計算屬性
計算屬性的本質就是一個方法
在使用計算屬性的時候,將這些名稱直接當作屬性來使用,並不會把計算屬性當作方法調用
引用的時候,必定不要加括號去調用,直接當作普通屬性去使用就能夠了
計算屬性的求值結果會被緩存起來,方便下次直接使用,若是計算屬性方法全部數據都沒有發生過變化,不會從新對屬性求值
輸出fullname三次,可是隻觸發了一次
computed始終都要return出去一個值
<body> <div id="app"> <input type="text" v-model="firstname"> + <input type="text" v-model="middlename"> + <input type="text" v-model="lastname"> = <!-- 引用的時候不加括號 --> <input type="text" v-model="fullname"> <p>{{ fullname }}</p> <p>{{ fullname }}</p> <p>{{ fullname }}</p> </div> <script> // 建立 Vue 實例,獲得 ViewModel var vm = new Vue({ el: '#app', data: { firstname: '', lastname: '', middlename: '' }, methods: {}, computed: { 'fullname': function () { console.log('ok') return this.firstname + '-' + this.middlename + '-' + this.lastname } } }); </script> </body>
默認只有getter的計算屬性
<div id="app"> <input type="text" v-model="firstName"> + <input type="text" v-model="lastName"> = <span>{{fullName}}</span> </div> <script> // 建立 Vue 實例,獲得 ViewModel var vm = new Vue({ el: '#app', data: { firstName: 'jack', lastName: 'chen' }, methods: {}, computed: { // 計算屬性; 特色:當計算屬性中因此來的任何一個 data 屬性改變以後,都會從新觸發 本計算屬性 的從新計算,從而更新 fullName 的值 fullName() { return this.firstName + ' - ' + this.lastName; } } }); </script>
定義有getter和setter的計算屬性
<div id="app"> <input type="text" v-model="firstName"> <input type="text" v-model="lastName"> <!-- 點擊按鈕從新爲 計算屬性 fullName 賦值 --> <input type="button" value="修改fullName" @click="changeName"> <span>{{fullName}}</span> </div> <script> // 建立 Vue 實例,獲得 ViewModel var vm = new Vue({ el: '#app', data: { firstName: 'jack', lastName: 'chen' }, methods: { changeName() { this.fullName = 'TOM - chen2'; } }, computed: { fullName: { get: function () { return this.firstName + ' - ' + this.lastName; }, set: function (newVal) { var parts = newVal.split(' - '); this.firstName = parts[0]; this.lastName = parts[1]; } } } }); </script>
computed屬性的結果會被緩存,除非依賴的響應式屬性變化纔會從新計算。主要看成屬性來使用。
methods方法表示一個具體的操做,主要書寫業務邏輯。
watch一個對象,鍵是須要觀察的表達式,值是對應回調函數。主要用來監聽某些特定數據的變化,從而進行某些具體的業務邏輯操做;能夠看做是computed和methods的結合體。
提供了一些最經常使用的NPM包鏡像地址,可以讓咱們快速的切換安裝包時候的服務器地址。
原來包剛一開始是隻存在於國外的NPM服務器,可是因爲網絡緣由,常常訪問不到,這時候,咱們能夠在國內,建立一個和官網徹底同樣的NPM服務器,只不過,數據都是從人家那裏拿過來的,除此以外,使用方式徹底同樣。
安裝運行
運行npm i nrm -g全局安裝nrm包
使用nrm ls查看當前全部可用的鏡像源地址以及當前所使用的鏡像源地址
使用nrm use npm或nrm use taobao切換不一樣的鏡像源地址
這裏默認是用npm裝包
切換用use 指令
nrm中的cnpm和cnpm性質不一樣,前者就是一個地址,後者是一個工具
普通頁面中使用vue
使用script標籤,引入vue包
在index頁面中,建立一個id爲app的div容器
經過new Vue獲得一個vm實例
在webpack中使用import Vue from ‘vue’導入的Vue構造函數,功能不完整,只提供了runtime-only的方式,並無提供像網頁中那樣的使用方式
這裏能夠將from後面引號中的內容修改爲vue.js文件的路徑,也就是經過script引入的那個文件,這麼作至關因而用script引入了js文件
或者修改package.json文件中,main屬性的值,入口文件由index.js改爲vue.js
或者設置vue被導入時候包的路徑,在webpack.config.js中和modules同級地建一個對象
resolve:{ alias:{ "vue$": "vue/dist/vue.js" } } //這種方法的import導入的是'vue',不是vue.js
vue結合webpack的時候,只能用render的方式進行渲染頁面
render: function (createElements) { return createElements(login) } //能夠用箭頭函數表示,只有一個參數,能夠省去括號,參數能夠簡寫。只有一條return語句,能夠省去return和花括號 render:c=>c(login)
導出
在login.vue中用export default方式導出節點
node向外暴露成員的方式model.exports={}
ES6中,也經過規範的形式,規定了ES6中如何導入和導出模塊
ES6中,導入模塊使用import,導入成員使用exports default
導入,導出不能混用,最好統一使用
向外暴露成員的時候,可使用任意的變量來接收
使用export default暴露,只能暴露一次,不然會報錯
組件中的data必須是function
export default { data() { // 注意:組件中的 data 必須是 function return { msg: "123" }; }, methods: { show() { console.log("調用了 login.vue 中的 show 方法"); } } };
exports暴露出去的成員,須要用花括號來接收,這種形式叫作按需導出
export var title='小星星' --- import m222,{title} from './test.js'
exports能夠向外暴露多個成員
在import的時候不須要 能夠不在花括號中定義,這就叫作按需導出
使用exports導出的成員必須嚴格按照導出時候的名稱來使用花括號按需接收
必定要用別的名字,這裏使用as
import m222,{title as title123,content} from './test.js'
安裝vue的包:cnpm i vue -S
安裝loader文件:cnpm i vue-template-complier -D
在main中導入vue模塊,import Vue from ‘vue’
新建一個純粹的組件文件login.vue,由template、script、style組成
main.js中導入login文件,import login from ‘./login.vue’
建立vm實例var vm=new Vue({el:'#app',render:c=>c(login)})
頁面中建立一個id爲app的div元素,做爲咱們vm實例要控制的區域
main.js中
render會把el指定的容器中,全部的內容都清空覆蓋,因此不要把路由的router-view和router-link直接寫到el所控制的元素中
App 這個組件,是經過VM實例的render函數,渲染出來的,render函數若是要渲染組件,渲染出來的組件,只能放到 el: '#app' 所指定的元素中
Account和GoodsList組件,是經過路由匹配監聽到的,這兩個組件,只能展現到屬於路由的<router-view></router-view> 中去。
//導入vue模塊 import Vue from 'vue' //導入vue-router包 import VueRouter from 'vue-router' //手動安裝VueRouter Vue.use(VueRouter) // 導入 app 組件,父組件 import app from './App.vue' // 導入 Account 組件,子組件 import account from './main/Account.vue' import goodslist from './main/GoodsList.vue' //建立路由對象 var router = new VueRouter({ routes: [ // account goodslist { path: '/account', component: account }, { path: '/goodslist', component: goodslist } ] }) var vm = new Vue({ el: '#app', render: c => c(app), // render 會把 el 指定的容器中,全部的內容都清空覆蓋,因此 不要 把 路由的 router-view 和 router-link 直接寫到 el 所控制的元素中 router // 4. 將路由對象掛載到 vm 上 })
webpack.config.js
因爲webpack是基於Node進行構建的,webpack的配置文件中,任何合法的Node代碼都是支持的
limit 給定的值,是圖片的大小,單位是 byte,若是咱們引用的圖片,大於或等於給定的 limit值,則不會被轉爲base64格式的字符串, 若是圖片小於給定的 limit 值,則會被轉爲base64的字符串
var path = require('path') // 在內存中,根據指定的模板頁面,生成一分內存中的首頁,同時自動把打包好的bundle注入到頁面底部 // 若是要配置插件,須要在導出的對象中,掛載一個 plugins 節點 var htmlWebpackPlugin = require('html-webpack-plugin') // 當以命令行形式運行 webpack 或 webpack-dev-server 的時候,工具會發現,咱們並無提供 要打包 的文件的 入口 和 出口文件,此時,他會檢查項目根目錄中的配置文件,並讀取這個文件,就拿到了導出的這個 配置對象,而後根據這個對象,進行打包構建 module.exports = { entry: path.join(__dirname, './src/main.js'), // 入口文件 output: { // 指定輸出選項 path: path.join(__dirname, './dist'), // 輸出路徑 filename: 'bundle.js' // 指定輸出文件的名稱 }, plugins: [ // 全部webpack 插件的配置節點 new htmlWebpackPlugin({ template: path.join(__dirname, './src/index.html'), // 指定模板文件路徑 filename: 'index.html' // 設置生成的內存頁面的名稱 }) ], module: { // 配置全部第三方loader 模塊的 rules: [ // 第三方模塊的匹配規則 // 處理 CSS 文件的 loader { test: /\.css$/, use: ['style-loader', 'css-loader'] }, // 處理 less 文件的 loader { test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'] }, // 處理 scss 文件的 loader { test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader'] }, // 處理 圖片路徑的 loader { test: /\.(jpg|png|gif|bmp|jpeg)$/, use: 'url-loader?limit=7631&name=[hash:8]-[name].[ext]' }, // 處理 字體文件的 loader { test: /\.(ttf|eot|svg|woff|woff2)$/, use: 'url-loader' }, // 配置 Babel 來轉換高級的ES語法 { test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ }, // 處理 .vue 文件的 loader { test: /\.vue$/, use: 'vue-loader' } ] }, resolve: { alias: { // 修改 Vue 被導入時候的包的路徑 // "vue$": "vue/dist/vue.js" } } }
vue模塊能夠實現嵌套
將main模塊中路由分發內容抽離到router中
main.js
import Vue from 'vue' // 1. 導入 vue-router 包 import VueRouter from 'vue-router' // 2. 手動安裝 VueRouter Vue.use(VueRouter) // 導入 app 組件 import app from './App.vue' // 導入 自定義路由模塊 import router from './router.js' var vm = new Vue({ el: '#app', render: c => c(app), router // 4. 將路由對象掛載到 vm 上 })
router.js
import VueRouter from 'vue-router' // 導入 Account 組件 import account from './main/Account.vue' import goodslist from './main/GoodsList.vue' // 導入Account的兩個子組件 import login from './subcom/login.vue' import register from './subcom/register.vue' // 3. 建立路由對象 var router = new VueRouter({ routes: [ // account goodslist { path: '/account', component: account, children: [ { path: 'login', component: login }, { path: 'register', component: register } ] }, { path: '/goodslist', component: goodslist } ] }) // 把路由對象暴露出去 export default router
普通的style標籤只能寫CSS樣式
style標籤有lang屬性,可讓lang屬性值爲scss,這樣就能夠識別scss樣式
只要style標籤是vue文件中定義的,須要加上scoped屬性,scope解決樣式的做用域問題
只要爲組件中style添加scope,就會對最外層的div添加一個自定義屬性,這個自定義屬性用來設置樣式,經過CSS的屬性選擇器實現的
使用export default和export導出模塊中的成員,對應ES5中的module.exports和export
使用import ** from ** 和import '路徑' 還有 import {a, b} from '模塊標識' 導入其餘模塊
使用箭頭函數:(a, b)=> { return a-b; }