Vue簡介
2014年誕生,2013年react,09年angularjs
作者: 尤雨溪
核心概念: 組件化 雙向數據流(基于ES5中的defineProperty來實現的),IE9才支持
angular核心: 模塊化 雙向數據綁定(臟檢測:一個數組($watch),性能弱)
開發一個登陸模塊,登陸需要顯示的頭部、底部、中部
組件:組合起來的一個部件(頭部、底部、中部)
細分代碼
頭部: 頁面、樣式、動態效果
代碼: templete style script
數據流
1向:js內存屬性發生改變,影響頁面的改變
1向:頁面的改變影響js內存屬性的改變
Vue實例對象
// 構造函數
var my = new Vue({
el: '#app', // 掛載點 (設置vue對象裝載到頁面位置)
template: '<div> {{ fruit }} </div>', // 模板
data: { // 數據
? ? fruit: 'apple'
}
});
data中的屬性會被代理到 my 對象中,可以使用 my.fruit 來獲取屬性值
vue常用指令
v-text
v-html
v-if
v-show
v-model
v-bind
代碼
<template>
<!-- 只能有一個根節點 -->
? <div>
? ? <pre>
? ? ? ? ?* v-text 是元素的innerText 只能在雙標簽元素中使用
? ? ? ? * v-html 是元素的innerHTML 不能包含<!-- {{ xxx }} -->
? ? ? ? * v-if? 元素是否移出或插入
? ? ? ? * v-show 元素是否隱藏或顯示
? ? ? ? * v-model雙向數據綁定
? ? ? ? * v-bind 單向數據綁定(內存js改變影響頁面,頁面改變不影響內存js)
? ? </pre>
? ? v-text:
? ? <span v-text="text"></span>
? ? <hr />
? ? v-html:
? ? <span v-html="html"></span>
? ? <hr />
? ? v-if:
? ? <div v-if="isShow" style="height: 100px; background-color:red;"></div>
? ? <hr />
? ? v-show:
? ? <div v-show="isShow" style="height: 100px; background-color:green;"></div>
? ? <hr />
? ? v-model:
? ? <input type="text" name="username" v-model="username" />
? ? {{ username }}<br/>
? ? <!--給下面的input value賦值 用 v-bind:value="username" -->
? ? <input type="text" name="" v-bind:value="username"? />
? ? <hr />
? </div>
</template>
<script>
export default {
? ? data(){
? ? ? ? return {
? ? ? ? ? ? text: '我是v-text內容',
? ? ? ? ? ? html: `
? ? ? ? ? ? ? ? <ul>
? ? ? ? ? ? ? ? ? ? <li>哈哈</li>
? ? ? ? ? ? ? ? ? ? <li>呵呵</li>
? ? ? ? ? ? ? ? </ul>
? ? ? ? ? ? `,
? ? ? ? ? ? isShow: false,
? ? ? ? ? ? username: 'admin'
? ? ? ? }
? ? }
}
</script>
<style>
</style>
class結合v-bind使用
需要根據可變的表達式的結果來給class賦值,就需要用到v-bind:class=”xxx”
v-bind:屬性名=”表達式”,最終表達式運算結束的結果賦值給該屬性?
簡化的寫法:?:屬性名="表達式"
class: 結果的分類
一個樣式: 返回字符串(三元表達式和 key和樣式的對象清單)
多個樣式: 返回對象(樣式做key,true或false做值)
<template>
? <div>
? ? <div v-bind:class="isRed? 'red' : 'green'">單個class樣式</div>
? ? <ul>
? ? ? ? <!-- 當stu.score = A 時 匹配red,當stu.score= B 時匹配green? -->
? ? ? ? <li v-for="stu in stus" :class="{'A': 'red', 'B': 'green'}[stu.score]"> {{ stu.name }}</li>
? ? </ul>
? ? <div :class="{'red': true, 'big': true}">多個class樣式</div>
? </div>
</template>
<script>
export default {
? ? data(){
? ? ? ? return {
? ? ? ? ? ? isRed: false,
? ? ? ? ? ? stus: [
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? name: 'jack',
? ? ? ? ? ? ? ? ? ? score: 'A'
? ? ? ? ? ? ? ? },
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? name: 'lucy',
? ? ? ? ? ? ? ? ? ? score: 'B'
? ? ? ? ? ? ? ? },
? ? ? ? ? ? ]
? ? ? ? }
? ? }
}
</script>
<style>
.red{
? ? background-color: red;
}
.green{
? ? background-color: green;
}
.big{
? ? font-size: 30px;
}
</style>
methods 和 v-on的使用
綁定事件的方法?
????????v-on:事件名="表達式||函數名"
????????簡寫:@事件名="表達式||函數名"
函數名如果沒有參數,可以省略() 只給一個函數名稱
函數的聲明需要在export default 這個對象的根屬性加上 methods 屬性中
凡是在template中使用函數或變量,不需要使用this
v-on高級用法
修飾符:
.stop - 調用 event.stopPropagation()。
.prevent - 調用 event.preventDefault()。
.capture - 添加事件偵聽器時使用 capture 模式。
.self - 只當事件是從偵聽器綁定的元素本身觸發時才觸發回調。
.{keyCode | keyAlias} - 只當事件是從特定鍵觸發時才觸發回調。
.native - 監聽組件根元素的原生事件。
.once - 只觸發一次回調。
.left - (2.2.0) 只當點擊鼠標左鍵時觸發。
.right - (2.2.0) 只當點擊鼠標右鍵時觸發。
.middle - (2.2.0) 只當點擊鼠標中鍵時觸發。
.passive - (2.3.0) 以 { passive: true } 模式添加偵聽器
用法:
綁定事件監聽器。事件類型由參數指定。表達式可以是一個方法的名字或一個內聯語句,如果沒有修飾符也可以省略。
從 2.4.0 開始,v-on 同樣支持不帶參數綁定一個事件/監聽器鍵值對的對象。注意當使用對象語法時,是不支持任何修飾器的。
用在普通元素上時,只能監聽 原生 DOM 事件。用在自定義元素組件上時,也可以監聽子組件觸發的自定義事件。
在監聽原生 DOM 事件時,方法以事件為唯一的參數。如果使用內聯語句,語句可以訪問一個 event屬性:v?on:click="handle(′ok′,event屬性:v?on:click="handle(′ok′,event)”。
<!-- 對象語法 (2.4.0+) -->
<button v-on="{ mousedown: doThis, mouseup: doThat }"></button>
<!-- 內聯語句 -->
<button v-on:click="doThat('hello', $event)"></button>
<!-- 縮寫 -->
<button @click="doThis"></button>
<!-- 停止冒泡 -->
<button @click.stop="doThis"></button>
<!-- 阻止默認行為 -->
<button @click.prevent="doThis"></button>
<!-- 阻止默認行為,沒有表達式 -->
<form @submit.prevent></form>
<!--? 串聯修飾符 -->
<button @click.stop.prevent="doThis"></button>
<!-- 鍵修飾符,鍵別名 -->
<input @keyup.enter="onEnter">
<!-- 鍵修飾符,鍵代碼 -->
<input @keyup.13="onEnter">
<!-- 點擊回調只會觸發一次 -->
<button v-on:click.once="doThis"></button>
<template>
? <div>
? ? <button v-on:click="isRed = !isRed">按鈕</button>
? ? <button v-on:click="change()">按鈕</button>
? ? <button @click="change">按鈕</button>
? </div>
</template>
<script>
export default {
? ? data(){
? ? ? ? return {
? ? ? ? ? ? isRed: false,
? ? ? ? ? ? stus: [
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? name: 'jack',
? ? ? ? ? ? ? ? ? ? score: 'A'
? ? ? ? ? ? ? ? },
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? name: 'lucy',
? ? ? ? ? ? ? ? ? ? score: 'B'
? ? ? ? ? ? ? ? },
? ? ? ? ? ? ]
? ? ? ? }
? ? },
? ? // 聲明函數,屬于組件對象
? ? methods: {
? ? ? ? // 包含多個函數名稱做key,函數提供做value
? ? ? ? change (){
? ? ? ? ? ? this.isRed = !this.isRed;
? ? ? ? ? ? this.stus.push({
? ? ? ? ? ? ? ? name: 'mick',
? ? ? ? ? ? ? ? score: 'A'
? ? ? ? ? ? });
? ? ? ? }
? ? }
}
</script>
<style>
.red{
? ? background-color: red;
}
.green{
? ? background-color: green;
}
.big{
? ? font-size: 30px;
}
</style>
v-for的使用
可以使用操作數組(item,index)
可以使用操作對象(value,key,index)
key 是類似于trank by的屬性,為了告訴vue,js中的元素和頁面的關聯,當刪除元素的時候,是單個元素的刪除而不是整版的替換,所有需要其關聯關系。2.0版本后必輸設置(性能)
<template>
? <div>
? ? <ul>
? ? ? ? <li v-for="(stu, index) in stus" v-bind:key="index">
? ? ? ? ? ? index:{{ index }} - stu:{{ stu }}
? ? ? ? </li>
? ? ? ? 使用對象的方式-滾動歌詞(時間做key,內容作為value)<hr />
? ? ? ? <li v-for="(value, key, index) in person" v-bind:key="index">
? ? ? ? ? ? value:{{ value }}-key:{{ key }}-index:{{ index }}
? ? ? ? </li>
? ? </ul>
? </div>
</template>
<script>
export default {
? ? data(){
? ? ? ? return {
? ? ? ? ? ? isRed: false,
? ? ? ? ? ? stus: [
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? name: 'jack',
? ? ? ? ? ? ? ? ? ? score: 'A'
? ? ? ? ? ? ? ? },
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? name: 'lucy',
? ? ? ? ? ? ? ? ? ? score: 'B'
? ? ? ? ? ? ? ? },
? ? ? ? ? ? ],
? ? ? ? ? ? person: {
? ? ? ? ? ? ? ? name: 'zhangsan',
? ? ? ? ? ? ? ? realname: '張三'
? ? ? ? ? ? }
? ? ? ? }
? ? }
}
</script>
<style>
.red{
? ? background-color: red;
}
.green{
? ? background-color: green;
}
.big{
? ? font-size: 30px;
}
</style>
簡單學生添加刪除案例
<template>
? <div>
? ? <ul>
? ? ? ? <li v-for="(stu, index) in stus" :key="stu.id" :class="{'A':'red','B':'blue','C':'green','D':'pink'}[stu.score]">
? ? ? ? ? ? {{ stu.name }} - {{ stu.score }}? ?
? ? ? ? ? ? <button @click="del(index)">刪除</button>
? ? ? ? </li>
? ? </ul>
? ? 學生姓名:<input type="text" name="name" v-model="name"/><br/>
? ? 學生成績:<input type="text" name="score" v-model="score"/><br/>
? ? <button @click="addStu">添加學生</button>
? </div>
</template>
<script>
export default {
? ? data(){
? ? ? ? return {
? ? ? ? ? ? isRed: false,
? ? ? ? ? ? name:'',
? ? ? ? ? ? score:'',
? ? ? ? ? ? stus: [
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? id: 1,
? ? ? ? ? ? ? ? ? ? name: '張三',
? ? ? ? ? ? ? ? ? ? score: 'A'
? ? ? ? ? ? ? ? },{
? ? ? ? ? ? ? ? ? ? id: 2,
? ? ? ? ? ? ? ? ? ? name: '張無忌',
? ? ? ? ? ? ? ? ? ? score: 'B'
? ? ? ? ? ? ? ? },{
? ? ? ? ? ? ? ? ? ? id: 3,
? ? ? ? ? ? ? ? ? ? name: '趙敏',
? ? ? ? ? ? ? ? ? ? score: 'C'
? ? ? ? ? ? ? ? },{
? ? ? ? ? ? ? ? ? ? id: 4,
? ? ? ? ? ? ? ? ? ? name: '殷素素',
? ? ? ? ? ? ? ? ? ? score: 'D'
? ? ? ? ? ? ? ? },
? ? ? ? ? ? ]
? ? ? ? }
? ? },
? ? // 聲明函數,屬于組件對象
? ? methods: {
? ? ? ? // 添加
? ? ? ? addStu (){
? ? ? ? ? ? // 獲取頁面輸入的值:v-model
? ? ? ? ? ? this.stus.push({
? ? ? ? ? ? ? ? id: 1,
? ? ? ? ? ? ? ? name: this.name,
? ? ? ? ? ? ? ? score: this.score
? ? ? ? ? ? });
? ? ? ? ? ? this.name = '';
? ? ? ? ? ? this.score = '';
? ? ? ? },
? ? ? ? // 刪除
? ? ? ? del (index){
? ? ? ? ? ? this.stus.splice(index, 1);
? ? ? ? }
? ? }
}
</script>
<style>
.red{
? ? background-color: red;
}
.green{
? ? background-color: green;
}
.blue{
? ? background-color: skyblue;
}
.pink{
? ? background-color: hotpink;
}
</style>
父子組件使用(父傳子)
父需要聲明子組件,引入子組件對象,聲明方式如下:
// 引入子組件
import 子組件對象名 from './xxx.vue';
// 聲明子組件
components: {
// 組件名(在模板中使用): 組件對象
}
全局組件,使用更為方便,不需要引入和聲明直接使用
在main.js中引入異常,在main.js中使用?vue.component('組件名',組件對象);
聲明為全局組件后,就可以直接通過組件名使用
父組件向自組件傳遞數據
父組件通過子組件標簽屬性將值傳遞?
? ??????方式一:常量?<header-vue 屬性名="常量值"></header-vue>
????????方式二:變量<header-vue :屬性名="變量名"></header-vue>
子組件使用該屬性值需要使用props 聲明?
? ??????在根屬性加?props: ['屬性名1','屬性名2'...]
????????在頁面中就可以直接使用?{{ 屬性名 }}
????????在js中可以直接使用 this.屬性名 訪問
????????export default{ data(){return{ } },
? ????????????// 接受父組件參數的設置
????????????? props:['textbody']
????????}
子組件向父組件通信(vuebus)
????????通過new Vue() 的一個對象,來$on(‘事件名’, fn(prop1, prop1)) 綁定事件
? ??????另一個組件引入統一個vuebus,來$emit(‘事件名’,prop1, prop2) 觸發事件
vue高級
? ? `? ?vue過濾器
? ? ? ? 獲取dom元素
????????mint-ui
????????vue組件的使用
? ? ? ? 組件間通信
????????vue-router使用
????????vue-resource發起http請求
????????axios
vue過濾器
content | 過濾器, vue中沒有提供默認過濾器,需要我們自定義過濾器
組件內過濾器 + 全局過濾器?
????組件內過濾器就是options中的一個filters的屬性(一個對象)?
? ? ????多個key就是不同的過濾器名,多個value就是與key對應的函數體
? ??Vue.filter(名, fn)
????如果名稱相同以局部為主
app.vue
<template>
? <div>
? ? 請輸入內容:
? ? <input type="text" name="name" v-model="name"/>
? ? 顯示:{{ name | myFilter}}
? </div>
</template>
<script>
? ? export default {
? ? ? ? // 自定義過濾器
? ? ? ? filters: {
? ? ? ? ? ? myFilter: function(value){
? ? ? ? ? ? ? ? // 輸入的內容翻轉: 轉換為數組->翻轉數組 ->轉換為字符串
? ? ? ? ? ? ? ? return value.split('').reverse().join('');
? ? ? ? ? ? }
? ? ? ? },
? ? ? ? data(){
? ? ? ? ? ? return {
? ? ? ? ? ? ? ? name:''
? ? ? ? ? ? }
? ? ? ? }
? ? }
</script>
<style scoped>
</style>
main.js
// 全局過濾器Vue.filter('myFilter1', function(value){
? ? return value.split('').reverse().join(',');
});
獲取DOM元素
前端框架就是為了減少dom操作,特定情況下也提供了的操作方式
在指定的元素上,添加ref=”名稱”
在獲取的地方加入 this.$refs.名稱?
????如果ref放在了原生DOM元素上,獲取的數據就是元素DOM對象
? ??如果ref放在組件對象上,獲取的就是組件對象
? ??獲取子組件DOM對象,通過this.refs.sub.refs.sub.el
事件
? ??created 完成數據初始化,未生成DOM
? ??mounted 將數據已經裝載到DOM之上,且DOM生成完畢
<template>
? <div>
? ? <sub-vue ref="sub"></sub-vue>
? ? <div ref="myDiv"></div>
? </div>
</template>
<script>
? ? import SubVue from './components/sub.vue';
? ? export default {
? ? ? ? data(){
? ? ? ? ? ? return {
? ? ? ? ? ? }
? ? ? ? },
? ? ? ? components: {
? ? ? ? ? ? SubVue: SubVue
? ? ? ? },
? ? ? ? // 組件創建后,數據已經完成初始化,但DOM還未完成
? ? ? ? created (){ // 事件的處理函數(created)
? ? ? ? ? ? console.log(this.$refs.sub);? ? ? ? ? // vue的組件對象
? ? ? ? ? ? this.$refs.sub.$el.innerHTML = '哈哈';? // 獲取vue組件對象對應的DOM對象
? ? ? ? ? ? console.log(this.$refs.myDiv);? ? ? ? // undefined 獲取不到
? ? ? ? },
? ? ? ? // 數據裝載到DOM上后,各種數據已經就位,將數據渲染到DOM上,DOM已經生產
? ? ? ? mounted (){ // 事件的處理函數(created)
? ? ? ? ? ? console.log(this.$refs.myDiv);// 獲取的原生DOM對象
? ? ? ? ? ? this.$refs.myDiv.innerHTML = '案發生的發生';
? ? ? ? }
? ? }
</script>
<style scoped>
</style>
vue-router
前端路由 核心就是錨點值的改變,根據不同的值,渲染指定DOM位置的不同數據
ui-router(anglar):錨點值改變,通過ajax獲取模板
vue中,模板數據不是通過ajax請求來的,而是調用函數獲取到模板內容
vue核心插件:?
? ??vue-router 路由
????vuex 管理全局共享數據
使用方式?
? ??1: 下載 npm install vue-router -S
????2: 引入 impot Router from 'vue-router'
????3: 安裝插件 Vue.use(Router)
????4: 創建路由對象并配置路由規則
????5: 將其李洋老師對象傳遞給Vue實例,options中
????6: 留坑
命名路由
需求:通過a標簽單擊實現頁面跳轉
使用 標簽
<a href="#/music">進入音樂</a>
<a href="#/movie">進入電影</a>
// 以上直接通過a標簽方式直接指定路徑名稱,如果錨點發生改變不好維護
<!-- 根據name跳轉(推薦使用該方式)-->
<router-link :to="{name: 'Music'}">進入音樂</router-link>
<router-link :to="{name: 'Movie'}">進入電影</router-link>
<!-- 根據path跳轉-->
<router-link to="/movie">進入電影</router-link>
router-link 參數傳遞
????vue-router 中掛在了兩個對象
? ? route(信息數據)router(功能函數)
? ??參數傳遞兩種方式:?
????????1:查詢字符串 query:{key: value} -> /detail?id=1
<router-link :to="{name: 'Detail',query: {id: user.id}}"> 查看詳情 </router-link>
? ? 路由path不用改:
? ? {
? ? ? path: '/detail',
? ? ? name: 'Detail',
? ? ? component: Detail
? ? }
2: 路徑字符串 params:{key: value} -> /detial/1
<router-link :to="{name: 'Detail',params: {id: user.id}}"> 查看詳情 </router-link>
? ? 路由path需要改:
? ? {
? ? ? path: '/detail/:id',
? ? ? name: 'Detail',
? ? ? component: Detail
? ? }
獲取參數?
????this.$route.query.id
????this.$route.params.id
編程式導航
不能保證用戶一定會單擊某些按鈕.
并且當前操作除了路由跳轉以外,還有一些別的附加操作
this.$router.go 根據瀏覽器記錄 前進 1 后退-1
this.$router.push(直接跳轉到某個頁面顯示)?
push參數: 字符串 /xxx
push參數: 對象 {name: ‘xxx’,query:{id:1}, params:{id:1,name:’zhangsan’}}
注意:有params的路由規則中一定記得在路由規則path中添加 path: ‘/movie/:id’,
<template>
? <div >
? ? ? ? <button @click="goMusic">跳轉到music</button>
? ? ? ? <button @click="goMovie">跳轉電影</button>
? ? ? ? <button @click="goBack">跳轉到上一頁</button>
? ? ? ? <button @click="testQuery">編程導航傳遞參數query方式</button>
? ? ? ? <button @click="testParams">編程導航傳遞參數params方式</button>
? </div>
</template>
<script>
export default {
? data () {
? ? return {
? ? }
? },
? methods: {
? ? goMusic (){
? ? ? ? this.$router.push('/music');
? ? },
? ? goMovie (){
? ? ? ? this.$router.push({
? ? ? ? ? ? name: 'Movie' // 路由規則 name值
? ? ? ? });
? ? },
? ? goBack (){
? ? ? ? this.$router.go(-1); //-1 上一次瀏覽器記錄 1 下一個瀏覽器記錄
? ? },
? ? testQuery (){
? ? ? ? ? ? // 查詢字符串方式: /music?id=1&name=zhagnsan
? ? ? ? ? ? this.$router.push({
? ? ? ? ? ? ? ? name: 'Music', // 路由規則 name值
? ? ? ? ? ? ? ? query: {
? ? ? ? ? ? ? ? ? ? id: 1,
? ? ? ? ? ? ? ? ? ? name: 'zhagnsan'
? ? ? ? ? ? ? ? }
? ? ? ? ? ? });
? ? },
? ? testParams (){
? ? ? ? ? ? // 查詢字符串方式: /movie/1
? ? ? ? ? ? this.$router.push({
? ? ? ? ? ? ? ? name: 'Movie', // 路由規則? name值
? ? ? ? ? ? ? ? params: {? ? ? // 路由規則? path: '/movie/:id',
? ? ? ? ? ? ? ? ? ? id: 1,
? ? ? ? ? ? ? ? ? ? name: 'zhagnsan'
? ? ? ? ? ? ? ? }
? ? ? ? ? ? });
? ? }
? }
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
原生監聽錨點值改變
window.addEventListener('hashchange', function(){
? ? var text = '';// 可以換成模板數據
? ? switch(location.hash){
? ? ? ? case '#/music':
? ? ? ? ? ? text = '各種音樂數據';
? ? ? ? ? ? break;
? ? ? ? case '#/movie':
? ? ? ? ? ? text = '各種電影數據';
? ? ? ? ? ? break;
? ? }
? ? document.getElementById('content').innerHTML = text;
});
重定向和404
重定向(寫死路徑名)?{path: '/', redirect: '/home'}
重定向(使用name) {path: '/', redirect: {name: 'home'}}
404:在路由規則的最后一個規則中寫一個很強大的匹配?
????{path: '*', component: notFoundVue}
? ??notFoundVue.vue: 404頁面組件
多視圖模式
? ??以前一個路由對應一個
? ??現在一個路由可以對應多個
? ??使用components 實現多視圖模式
<router-view name="header"></router-view>
? ? <router-view ></router-view>? 沒有name使用default
? ? <router-view name="footer"></router-view>
? ? routes: [
? ? ? ? {
? ? ? ? ? path: '/',
? ? ? ? ? name: 'Home',
? ? ? ? ? // 注意這里名稱為components
? ? ? ? ? components: {
? ? ? ? ? ? header: HeaderVue,
? ? ? ? ? ? footer: FooterVue,
? ? ? ? ? ? default: Home
? ? ? ? ? }
? ? ? ? }
? ? ]
嵌套路由
借助 vue-router,使用嵌套路由配置,就可以很簡單地表達這種關系。
????用單頁實現多頁應用,使用復雜的嵌套路由完成
????開發中一般都會用到嵌套路由
????視圖包含視圖
? ? 路由父子級關系路由配置
routes: [
{ path: '/user/:id', component: User,
children: [
{
// 當 /user/:id/profile 匹配成功,
// UserProfile 會被渲染在 User 的 <router-view> 中
path: 'profile',
component: UserProfile
},
{
// 當 /user/:id/posts 匹配成功
// UserPosts 會被渲染在 User 的 <router-view> 中
path: 'posts',
component: UserPosts
}
]
}
]