VUE入門

追夢NAN發表於2020-06-18

1.vue.js的快速入門使用

1.1 vue.js庫的下載

vue.js是目前前端web開發最流行的工具庫,由尤雨溪在2014年2月釋出的。

另外幾個常見的工具庫:react.js /angular.js

官方網站:

​ 中文:https://cn.vuejs.org/

​ 英文:https://vuejs.org/

官方文件:https://cn.vuejs.org/v2/guide/

vue.js目前有1.x、2.x和3.x 版本,我們學習2.x版本的。

1.2 vue.js庫的基本使用

在github下載:

在官網下載地址: https://cn.vuejs.org/v2/guide/installation.html

vue的引入類似於jQuery,開發中可以使用開發版本vue.js,產品上線要換成vue.min.js。

下圖是github網站下載的vue.js目錄

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
    window.onload = function(){
      	// vue.js的程式碼開始於一個Vue物件。所以每次運算元據都要宣告Vue物件開始。
        var vm = new Vue({
            el:'#app',   // 設定當前vue物件要控制的標籤範圍。
            data:{  // data是將要展示到HTML標籤元素中的資料。
              message: 'hello world!',
            }
        });
    }
    </script>
</head>
<body>
<div id="app">
    <!-- {{ message }} 表示把vue物件裡面data屬性中的對應資料輸出到頁面中 -->
    <!-- 在雙標籤中顯示資料要通過{{  }}來完成 -->
    <p>{{ message }}</p>
</div>
</body>
</html>

總結:

1. vue的使用要從建立Vue物件開始
   var vm = new Vue();
   
2. 建立vue物件的時候,需要傳遞引數,是json物件,json物件物件必須至少有兩個屬性成員
   var vm = new Vue({
     el:"#app",
	 	 data: {
         資料變數:"變數值",
         資料變數:"變數值",
         資料變數:"變數值",
     },
   });
   
   el:設定vue可以操作的html內容範圍,值一般就是css的id選擇器。
   data: 儲存vue.js中要顯示到html頁面的資料。
   
3. vue.js要控制器的內容外圍,必須先通過id來設定。
  <div id="app">
      <h1>{{message}}</h1>
      <p>{{message}}</p>
  </div>

1.3 vue.js的M-V-VM思想

MVVM 是Model-View-ViewModel 的縮寫,它是一種基於前端開發的架構模式。

Model 指代的就是vue物件的data屬性裡面的資料。這裡的資料要顯示到頁面中。

View 指代的就是vue中資料要顯示的HTML頁面,在vue中,也稱之為“檢視模板” 。

ViewModel 指代的是vue.js中我們編寫程式碼時的vm物件了,它是vue.js的核心,負責連線 View 和 Model,保證檢視和資料的一致性,所以前面程式碼中,data裡面的資料被顯示中p標籤中就是vm物件自動完成的。

編寫程式碼,讓我們更加清晰的瞭解MVVM:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        window.onload = function(){
            // vm檢視控制物件,會實時監控,時刻保證data屬性中的資料和html檢視中的內容保持一致:
            vm = new Vue({
                el: "#app",
                data:{
                    img: "logo.png",
                    num: 1,
                    content:"<h1>大標題</h1>",
                    url:"http://www.baidu.com"
                },
                // 事件觸發時呼叫的方法,或者其他屬性方法中呼叫的內部方法
                methods:{
                    show(){
                        alert("hello")
                    }
                }
            });
        }
        // js中也有三元表示式,也叫三元運算子
        // 格式:
        //   條件?true:false;
    </script>
</head>
<body>
<div id="app">
    <input type="text" v-model="img">
    {{"圖片地址是:"+img}}
    <span v-html="img.toLocaleUpperCase()"></span>
    <img :src="img">
    {{num%2==0?"偶數":"奇數"}}<br>
    <p v-html="content"></p>
    <p v-text="content"></p>
    {{content}}<br>
<!--    <a v-bind:href="url">路飛</a>-->
    <a :href="url">百度</a>

    <p @click="show">內容</p>
<!--    <p v-on:click="show">內容</p>-->
</div>
</body>
</html>

在瀏覽器中可以在 console.log通過 vm物件可以直接訪問el和data屬性,甚至可以訪問data裡面的資料

console.log(vm.$el)     # #box  vm物件可以控制的範圍
console.log(vm.$data);  # vm物件要顯示到頁面中的資料
console.log(vm.$data.message);  # 訪問data裡面的資料
console.log(vm.message);# 這個 message就是data裡面宣告的資料,也可以使用 vm.變數名顯示其他資料,message只是舉例.

總結:

1. 如果要輸出data裡面的資料作為普通標籤的內容,需要使用{{  }}
   用法:
      vue物件的data屬性:
          data:{
            name:"小明",
          }
      標籤元素:
      		<h1>{{ name }}</h1>
2. 如果要輸出data裡面的資料作為表單元素的值,需要使用vue.js提供的元素屬性v-model
   用法:
      vue物件的data屬性:
          data:{
            name:"小明",
          }
      表單元素:
      		<input v-model="name">
      
   使用v-model把data裡面的資料顯示到表單元素以後,一旦使用者修改表單元素的值,則data裡面對應資料的值也會隨之發生改變,甚至,頁面中凡是使用了這個資料都會發生變化。
3. 可以在普通標籤中使用{{  }} 或者 v-html 來輸出data裡面的資料
   <h1>{{message}}</h1>
   
4. 可以在表單標籤中使用v-model屬性來輸出data裡面的資料,同時還可以修改data裡面的資料
   <input type="text" v-model="username">

2. 常用指令

指令 (Directives) 是帶有“v-”字首的特殊屬性。每一個指令在vue中都有固定的作用。

在vue中,提供了很多指令,常用的有:v-if、v-model、v-for等等。

指令會在vm物件的data屬性的資料發生變化時,會同時改變元素中的其控制的內容或屬性。

因為vue的歷史版本原因,所以有一部分指令都有兩種寫法:

vue1.x寫法             vue2.x的寫法
v-html         ---->   {{ 普通文字 }}   # vue2.x 也支援v-html,v-text,輸出html程式碼的內容
v-bind:屬性名   ---->   :屬性
v-on:事件名     ---->   @事件名

2.1 操作屬性

格式:

<標籤名 :標籤屬性="data屬性"></標籤名>
<p :title="str1">{{ str1 }}</p> <!-- 也可以使用v-html顯示雙標籤的內容,{{  }} 是簡寫 -->
<a :href="url2">淘寶</a>

顯示wifi密碼效果:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
    <div id="app">
        <input :type="tp">
        <input type="button" @mousedown="down" @mouseup="up" v-model="message">
    </div>
    <script>
        var vm = new Vue({
            el:"#app",
            data:{
                message:"顯示密碼",
                tp:"password",
            },
            methods:{
                down(){
                    // 在methods中的子方法裡面要操作data的屬性,可以使用this.屬性值
                    this.tp="text";
                    this.message="隱藏密碼";
                },
                up(){
                    this.tp="password";
                    this.message="顯示密碼";
                }
            }
        })
    </script>
</body>
</html>

2.2 事件繫結

有兩種事件操作的寫法,@事件名 和 v-on:事件名

<button @click="num+=5">按鈕2</button>

總結:

1. 使用@事件名來進行事件的繫結
   語法:
      <h1 @click="num++">{{num}}</h1>

2. 繫結的事件的事件名,全部都是js的事件名:
   @submit   --->  onsubmit
   @focus    --->  onfocus
   ....


完成商城購物車中的商品增加減少數量

步驟:

  1. 給vue物件新增運算元據的方法
  2. 在標籤中使用指令呼叫運算元據的方法
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
    <button @click="add">+</button>
    <input type="text" v-model="num">
    <button @click="sub">-</button>
    單價:{{price}}
<!--    保留兩位小數-->
    <p>總計:{{total.toFixed(2)}}</p>
</div>
<script>
    var vm = new Vue({
        el:"#app",
        data:{
            num: 1,
            price: 39.8,
            total: 39.8,
        },
        methods:{
            add(){
                // 增加數量 轉化數字相加
                this.num = parseInt(this.num) + 1;
                this.calc();
            },
            sub(){
               // 減少數量
               if(this.num<=1){
                   return;
               }
               this.num -= 1;
               this.calc();
            },
            calc(){
               // 計算總價
               this.total = this.price * this.num;
            }
        }
    })
</script>
</body>
</html>

2.3 操作樣式

2.3.1 控制標籤class類名

格式:
   <h1 :class="值">元素</h1>  值可以是字串、物件、物件名、陣列

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <style>
    .box{
        width: 100px;
        height: 100px;
        background-color: #ff6666;
    }
    .box1{
        border-radius: 22px;
    }
    .box2{
        width: 200px;
        height: 200px;
        background-color: #66f;
    }
    </style>
</head>
<body>
<div id="app">
    <div :class="cls"></div>
    <div :class="[cls,cls2]"></div>
    <div :class="{box1:show_box1,box2:show_box2}"></div>
</div>
<script>
    var vm = new Vue({
        el:"#app",
        data:{
            cls: "box",
            cls2: "box1",
            // 布林值變數如果是true,則不會新增物件的屬性名作為樣式
            show_box1:false,
            show_box2:true,
        },
    })
</script>
</body>
</html>

總結:

1. 給元素繫結class類名,最常用的就是第二種。
    vue物件的data資料:
        data:{
          myObj:{
            complete:true,
            uncomplete:false,
          }
        }

		html元素:    
    		<div class="box" :class="myObj">2222</div>
    最終瀏覽器效果:
		    <div class="box complete">2222</div>

控制白天黑夜

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <style>
    .bg{
        width: 300px;
        height: 1000px;
    }
    .baitian{
        background-color: white;
    }
    .heiye{
        background-color: #666;
    }
    </style>
</head>
<body>
<div id="app" class="bg" :class="{baitian:is_show,heiye:is_show_2}">
    <button @click="change">關燈</button>
</div>
<script>
    var vm = new Vue({
        el:"#app",
        data:{
            is_show:true,
            is_show_2:false
        },
        methods:{
            change(){
                if(this.is_show==true){
                    this.is_show=false;
                    this.is_show_2=true;
                }else{
                    this.is_show=true;
                    this.is_show_2=false;
                }
            }
        }
    })
</script>
</body>
</html>

2.3.2 控制標籤style樣式

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
    <div style="width:100px;height:100px;" :style="{backgroundColor:`#6f6`}"></div>
    <div style="" :style="box"></div>
    <div style="" :style="[box,box2]"></div>
</div>
<script>
    var vm = new Vue({
        el:"#app",
        data:{
            box:{
                backgroundColor:`#6f6`,
                width:"100px",
                height:"100px",
            },
            box2:{
                borderRadius:"50px", // borderRadius 邊框圓角
            }
        },

    })
</script>
</body>
</html>

2.3.2 例項-vue版本選項卡

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        #card{
            width: 500px;
            height: 350px;
        }
        .title{
            height:50px;
        }
        .title span{
            width: 100px;
            height: 50px;
            background-color:#ccc;
            display: inline-block;
            line-height: 50px; /* 設定行和當前元素的高度相等,就可以讓文字內容上下居中 */
            text-align:center;
        }
        .content .list{
            width: 500px;
            height: 300px;
            background-color: yellow;
            display: none;
        }
        .content .active{
            display: block;
        }
        .title .current{
            background-color:yellow;
        }
    </style>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>

    <div id="card">
        <div class="title">
            <span @mouseover="num=1" :class="num==1?'current':''">國內新聞</span>
            <span @mouseover="num=2" :class="num==2?'current':''">國際新聞</span>
            <span @mouseover="num=3" :class="num==3?'current':''">銀河新聞</span>
        </div>
        <div class="content">
            <div class="list" :class="num==1?'active':''">國內新聞列表</div>
            <div class="list" :class="num==2?'active':''">國際新聞列表</div>
            <div class="list" :class="num==3?'active':''">銀河新聞列表</div>
        </div>
    </div>
    <script>
        // 實現一個js的特效時:關鍵是找出3個資料出來
        // 1. 使用者操作的元素
        // 2. 使用者觸發的事件
        // 3. 事件觸發以後的效果是什麼?
        var vm = new Vue({
            el:"#card",
            data:{
                num:1,
            }
        })
    </script>
</body>
</html>
思路:
當使用者點選標題欄的按鈕[span]時,顯示對應索引下標的內容塊[.list]
程式碼實現:

2.4 條件渲染指令

vue中提供了兩個指令可以用於判斷是否要顯示元素,分別是v-if和v-show。

2.4.1 v-if

  標籤元素:
      <!-- vue物件最終會把條件的結果變成布林值 -->
			<h1 v-if="ok">Yes</h1>
  data資料:
  		data:{
      		ok:false    // true則是顯示,false是隱藏
      }

2.4.2 v-else

v-else指令來表示 v-if 的“else 塊”,v-else 元素必須緊跟在帶 v-if 或者 v-else-if 的元素的後面,否則它將不會被識別。

  標籤元素:
			<h1 v-if="ok">Yes</h1>
			<h1 v-else>No</h1>
  data資料:
  		data:{
      		ok:false    // true則是顯示,false是隱藏
      }

2.4.3 v-else-if

可以出現多個v-else-if語句,但是v-else-if之前必須有一個v-if開頭。後面可以跟著v-else,也可以沒有。

  標籤元素:
			<h1 v-if="num==1">num的值為1</h1>
			<h1 v-else-if="num==2">num的值為2</h1>
		  <h1 v-else>num的值是{{num}}</h1>
  data資料:
  		data:{
      		num:2
      }

2.4.4 v-show

用法和v-if大致一樣,區別在於2點:

  1. v-show後面不能v-else或者v-else-if
  2. v-show隱藏元素時,使用的是display:none來隱藏的,而v-if是直接從HTML文件中移除元素[ DOM操作中的remove ]
  標籤元素:
			<h1 v-show="ok">Hello!</h1>
  data資料:
  		data:{
      		ok:false    // true則是顯示,false是隱藏
      }

2.5 列表渲染指令

在vue中,可以通過v-for指令可以將一組資料渲染到頁面中,資料可以是陣列或者物件。

資料是陣列

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>

    <div id="app">
        <table border="1" width="800px">
            <tr>
                <th>序號</th>
                <th>id</th>
                <th>姓名</th>
                <th>年齡</th>
            </tr>
            <tr v-for="v,k in student_list">
                <td>{{k+1}}</td>
                <td>{{v.id}}</td>
                <td>{{v.name}}</td>
                <td>{{v.age}}</td>
            </tr>

        </table>
    </div>
        <script>
            var vm1 = new Vue({
                el:"#app",
                data:{
                    student_list:[
                        {"id":1,"name":"zbb","age":18},
                        {"id":1,"name":"zbb","age":18},
                        {"id":1,"name":"zbb","age":18},
                        {"id":1,"name":"zbb","age":18},
                        {"id":1,"name":"zbb","age":18},
                    ]
                },
            })
        </script>

</body>
</html>

資料是物件:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
        <ul id="app">
<!--            v是每一個value值,j是每一個鍵名-->
            <li v-for="v, j in book">{{j}}:{{v}}</li>
        </ul>


        <script>
            var vm1 = new Vue({
                el:"#app",
                data:{
                    book: {
                        // "attr":"value"
                        "id":11,
                        "title":"圖書名稱1",
                        "price":200
                    },
                },
            })
        </script>

</body>
</html>

練習:

goods:[
	{"name":"python入門","price":150},
	{"name":"python進階","price":100},
	{"name":"python高階","price":75},
	{"name":"python研究","price":60},
	{"name":"python放棄","price":110},
]

# 把上面的資料採用table表格輸出到頁面,價格大於60的資料需要新增背景色橙色[orange]

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<style>
    .orange{
        background: orange ;
    }
</style>
<body>

<div id="app">
    <table border="1" width="800px">
        <tr>
            <th>序號</th>
            <th>課程</th>
            <th>價格</th>
        </tr>
        <tr v-for="v,k in goods" :class="v.price>60?'orange':''">
            <td>{{k+1}}</td>
            <td>{{v.name}}</td>
            <td>{{v.price}}</td>
        </tr>

    </table>
</div>
<script>
    var vm1 = new Vue({
        el: "#app",
        data: {
            goods: [
                {"name": "python入門", "price": 150},
                {"name": "python進階", "price": 100},
                {"name": "python高階", "price": 75},
                {"name": "python研究", "price": 60},
                {"name": "python放棄", "price": 110},
            ]
        },
    })
</script>
</body>
</html>

2.6 在表中新增資料

第一步:

迴圈表格, 編寫新增對話方塊, 更新列表,編寫刪除按鈕

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<style>
    .win {
        background: orange;
        width: 300px;
        height: 100px;
        position: fixed;
        top: 0;
        bottom: 0;
        left: 0;
        right: 0;
        margin: auto;
    }
</style>
<body>

<div id="app">
    <table border="1" width="800px" align="center">
        <td colspan="5">
            <button @click="win_show = 1">add</button>
        </td>
        <tr>
            <th>序號</th>
            <th>課程</th>
            <th>價格</th>
            <th>按鈕</th>
        </tr>
        <tr v-for="v,k in goods">
            <td>{{k+1}}</td>
            <td>{{v.name}}</td>
            <td>{{v.price}}</td>
            <td>
                <button>edit</button>
                <button @click="del(k)">del</button>
            </td>
        </tr>

    </table>
    <div class="win" v-show=win_show>
        <lable>課程:<input type="text" v-model="name"></lable>
        <br>
        <lable>價格:<input type="text" v-model="price"></lable>
        <br>
        <button @click="sava">確定</button>
        <button @click="close">取消</button>
    </div>
</div>
<script>
    var vm = new Vue({
        el: "#app",
        data: {
            win_show: false,
            goods: [
                {"name": "python入門", "price": 150},
                {"name": "python進階", "price": 100},
                {"name": "python高階", "price": 75},
                {"name": "python研究", "price": 60},
                {"name": "python放棄", "price": 110},
            ],
            name: "",
            price: "",
        },
        methods: {  
            sava() {
                // 追加成員
                this.goods.push({
                    "name": this.name,
                    "price": this.price
                });
                this.close();
            },
            close() {
                // 關閉視窗
                this.win_show = false;
                // 清空視窗中的資料
                this.title = "";
                this.number = "";
                this.price = ""

            },
            del(k){
                this.goods.splice(k,1)
            }
        }
    })
</script>
</body>
</html>

第二步,編輯按鈕

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<style>
    .win {
        background: orange;
        width: 300px;
        height: 100px;
        position: fixed;
        top: 0;
        bottom: 0;
        left: 0;
        right: 0;
        margin: auto;
    }
</style>
<body>

<div id="app">
    <table border="1" width="800px" align="center">
        <td colspan="5">
            <button @click="win_show = 1">add</button>
        </td>
        <tr>
            <th>序號</th>
            <th>課程</th>
            <th>價格</th>
            <th>按鈕</th>
        </tr>
        <tr v-for="v,k in goods">
            <td>{{k+1}}</td>
            <td>{{v.name}}</td>
            <td>{{v.price}}</td>
            <td>
                <button @click="edit(k)">edit</button>
                <button @click="del(k)">del</button>
            </td>
        </tr>

    </table>
    <div class="win" v-show=win_show>
        <lable>課程:<input type="text" v-model="name"></lable>
        <br>
        <lable>價格:<input type="text" v-model="price"></lable>
        <br>
        <button @click="sava">確定</button>
        <button @click="close">取消</button>
    </div>
</div>
<script>
    var vm = new Vue({
        el: "#app",
        data: {
            win_show: false,
            goods: [
                {"name": "python入門", "price": 150},
                {"name": "python進階", "price": 100},
                {"name": "python高階", "price": 75},
                {"name": "python研究", "price": 60},
                {"name": "python放棄", "price": 110},
            ],
            name: "",
            price: "",
            current: -1, //沒有編輯任何的內容
        },
        methods: {
            sava() {
                if (this.current == -1) {
                    // 追加成員
                    this.goods.push({
                        "name": this.name,
                        "price": this.price
                    });
                }else{
                    //編輯
                    this.goods[this.current].name=this.name;
                    this.goods[this.current].price=this.price;

                }
                    this.close();

            },
            close() {
                // 關閉視窗
                this.win_show = false;
                //重置編輯操作
                this.current=-1
                // 清空視窗中的資料
                this.title = "";
                this.number = "";
                this.price = ""

            },
            del(k) {
                this.goods.splice(k, 1)
            },
            edit(k){
                this.current=k;
                this.name=this.goods[k].name;
                this.price=this.goods[k].price;
                this.win_show=1;

            }
        }
    })
</script>
</body>
</html>

3. Vue物件提供的屬性功能

3.1 過濾器

過濾器,就是vue允許開發者自定義的文字格式化函式,可以使用在兩個地方:輸出內容和運算元據中。

定義過濾器的方式有兩種。

3.1.1 使用Vue.filter()進行全域性定義

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="js/filters.js"></script>
</head>
<body>
    <div id="box">
        <p>{{price|RMB}}</p>
    </div>
    <script>
    /*
     * // 過濾器,有兩種:
       // 全域性過濾器, 通過Vue.filter("過濾器名稱",匿名函式)
       Vue.filter("RMB", function(v){
          return "¥"+v;
       });
     */
    var vm = new Vue({
        el:"#box",
        data:{
            price:30.5
        }
    })
    </script>
</body>
</html>

3.1.2 在vue物件中通過filters屬性區域性

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="box">
    <p>{{price|RMB}}</p>
</div>
<script>
    var vm = new Vue({
        el:"#box",
        data:{
            price:30.5
        },
        filters:{
            RMB(v){
                return "¥"+v;
            }
        }
    })
</script>
</body>
</html>

3.4 計算和偵聽屬性

3.4.1 計算屬性

我們之前學習過字串反轉,如果直接把反轉的程式碼寫在元素中,則會使得其他同事在開發時時不易發現資料被調整了,所以vue提供了一個計算屬性(computed),可以讓我們把調整data資料的程式碼存在在該屬性中。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="box">
    <p>{{price}}</p>
    <p>{{price2}}</p>
</div>
<script>
    // 當我們需要針對data的資料盡心調整成另一個變數,留作後面其他地方進行運算使用時,可以使用計算屬性得出一個新的變數
    var vm = new Vue({
        el: "#box",
        data: {
            price: 30.5
        },
        // 計算屬性
        computed: {
            price2: function () {
                return this.price.toFixed(2);
            }
        }
    })
</script>
</body>
</html>

3.4.2 監聽屬性

偵聽屬性,可以幫助我們偵聽data某個資料的變化,從而做相應的自定義操作。

偵聽屬性是一個物件,它的鍵是要監聽的物件或者變數,值一般是函式,當偵聽的data資料發生變化時,會自定執行的對應函式,這個函式在被呼叫時,vue會傳入兩個形參,第一個是變化前的資料值,第二個是變化後的資料值。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="box">
    數量:<input type="text" v-model="num">
    單價:<input type="text" v-model="price">
    總價:{{total}}
</div>
<script>
    var vm = new Vue({
        el: "#box",
        data: {
            num: 0,
            price: 30.5,
            total: 0
        },
        watch: {
            num(newval, oldval) {
                console.log("修改後num="+newval);
                console.log("修改前num="+oldval);
                this.total = this.price * this.num;
            },
            price() {
                this.total = this.price * this.num;
            }
        }
    })
</script>
</body>
</html>

3.5 vue物件的生命週期

每個Vue物件在建立時都要經過一系列的初始化過程。在這個過程中Vue.js會自動執行一些叫做生命週期的的鉤子函式,我們可以使用這些函式,在物件建立的不同階段加上我們需要的程式碼,實現特定的功能。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="box">
    {{num}}
    <input type="text" v-model="num">
</div>
<script>
    var vm = new Vue({
        el: "#box",   
        data: {
            num: 30,
        },
        beforeCreate() {
            // 這裡的程式碼執行時,vm物件尚未建立,所以data中的資料是無法操作
            // console.log(this.num); // undefined
        },
        created() {
            // 這裡的程式碼執行時,vm物件已經建立完成,但是還沒有把資料和檢視模板進行繫結
            // console.log(this.num); // data的資料已經可以操作了。
            // console.log(this.$el); // 此時還沒有繫結檢視
            // 這裡可以用於編寫從後端獲取資料的程式碼
        },
        beforeMount() {
            // 這裡的程式碼執行時,已經繫結了檢視,但是沒有更新檢視中的資料
            console.log(this.$el.innerHTML);
        },
        mounted() {
            // 這裡的程式碼執行時,已經把data中的資料替換了模板檢視中對應的內容了
            console.log(this.$el);
            // 這裡可以用於編寫一些需要操作檢視額初始化程式碼
        },
        beforeUpdate() {
            // 更新html模板的資料之前
            console.log(this.num);
            console.log(this.$el.innerHTML)
        },
        updated() {
            // 更新html模板的資料之後
            console.log(this.num);
            console.log(this.$el.innerHTML)
        }
    })
</script>
</body>
</html>

總結:

在vue使用的過程中,如果要初始化操作,把初始化操作的程式碼放在 mounted 中執行。
mounted階段就是在vm物件已經把data資料實現到頁面以後。一般頁面初始化使用。例如,使用者訪問頁面載入成功以後,就要執行的ajax請求。

另一個就是created,這個階段就是在 vue物件建立以後,把ajax請求後端資料的程式碼放進 created

3.2 阻止事件冒泡和重新整理頁面

什麼是事件冒泡

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body  onclick="alert('body')">
    <div onclick="alert('div')">
        <button>按鈕</button>
    </div>
    <script>
    // 事件,event,在js中表示使用者和瀏覽器之間進行的一次互動過程
    // 事件在觸發時,就會有一個事件物件來記錄整個事件發生的過程和發生的位置
    // 從事件發生位置由內及外,根據標籤之間父子巢狀關係,逐層往外傳播,讓父級元素觸發同類事件,這種事件的傳遞方式,就是 事件冒泡
    // 事件冒泡有好,有壞。
    // 好處就是可以利用這種機制,實現事件委託
    // 壞處就是當前元素的父級元素有同類事件,會隨著冒泡直接全部執行
    </script>
</body>
</html>

使用.stop和.prevent

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="box" @click="show2">
    <!-- @click.stop來阻止事件冒泡 -->
    <button @click.stop="show">按鈕</button>
    <!-- @click.prevent來阻止標籤重新整理 -->
    <a href="" @click.prevent="show3">a連結</a>
</div>
<script>
    var vm = new Vue({
        el: "#box",
        data: {},
        methods: {
            show() {
                alert("按鈕");
            },
            show2() {
                // alert("父元素");
            },
            show3() {
                console.log("一句話");
            }
        }
    })
</script>
</body>
</html>

3.3 綜合案例-todolist

我的計劃列表

html程式碼:

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>todolist</title>
	<style type="text/css">
		.list_con{
			width:600px;
			margin:50px auto 0;
		}
		.inputtxt{
			width:550px;
			height:30px;
			border:1px solid #ccc;
			padding:0px;
			text-indent:10px;
		}
		.inputbtn{
			width:40px;
			height:32px;
			padding:0px;
			border:1px solid #ccc;
		}
		.list{
			margin:0;
			padding:0;
			list-style:none;
			margin-top:20px;
		}
		.list li{
			height:40px;
			line-height:40px;
			border-bottom:1px solid #ccc;
		}

		.list li span{
			float:left;
		}

		.list li a{
			float:right;
			text-decoration:none;
			margin:0 10px;
		}
	</style>
</head>
<body>
	<div class="list_con">
		<h2>To do list</h2>
		<input type="text" name="" id="txt1" class="inputtxt">
		<input type="button" name="" value="增加" id="btn1" class="inputbtn">

		<ul id="list" class="list">
			<!-- javascript:; # 阻止a標籤跳轉 -->
			<li>
				<span>學習html</span>
				<a href="javascript:;" class="up"> ↑ </a>
				<a href="javascript:;" class="down"> ↓ </a>
				<a href="javascript:;" class="del">刪除</a>
			</li>
			<li><span>學習css</span><a href="javascript:;" class="up"> ↑ </a><a href="javascript:;" class="down"> ↓ </a><a href="javascript:;" class="del">刪除</a></li>
			<li><span>學習javascript</span><a href="javascript:;" class="up"> ↑ </a><a href="javascript:;" class="down"> ↓ </a><a href="javascript:;" class="del">刪除</a></li>
		</ul>
	</div>
</body>
</html>

特效實現效果:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>todolist</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <style type="text/css">
        .list_con {
            width: 600px;
            margin: 50px auto 0;
        }

        .inputtxt {
            width: 550px;
            height: 30px;
            border: 1px solid #ccc;
            padding: 0px;
            text-indent: 10px;
        }

        .inputbtn {
            width: 40px;
            height: 32px;
            padding: 0px;
            border: 1px solid #ccc;
        }

        .list {
            margin: 0;
            padding: 0;
            list-style: none;
            margin-top: 20px;
        }

        .list li {
            height: 40px;
            line-height: 40px;
            border-bottom: 1px solid #ccc;
        }

        .list li span {
            float: left;
        }

        .list li a {
            float: right;
            text-decoration: none;
            margin: 0 10px;
        }
    </style>
</head>
<body>
<div class="list_con" id="app">
    <h2>To do list</h2>
    <input type="text" v-model="text" id="txt1" class="inputtxt">
    <input type="button" @click="add" value="增加" id="btn1" class="inputbtn">

    <ul id="list" class="list">
        <!-- javascript:; # 阻止a標籤跳轉 -->
        <li v-for="item,key in todolist">
            <span>{{item}}</span>
            <a href="javascript:;" @click="up(key)" class="up"> ↑ </a>
            <a href="javascript:;" @click="down(key)" class="down"> ↓ </a>
            <a href="javascript:;" @click="del(key)" class="del">刪除</a>
        </li>
    </ul>
</div>
<script>
    var vm = new Vue({
        el: "#app",
        data: {
            text: "",
            todolist: [
                "學習html",
                "學習css",
                "學習javascript",
            ]
        },
        methods: {
            add() {
                this.todolist.push(this.text);
                this.text = "";
            },
            del(key) {
                // splice 萬能函式
                // 刪除和替換
                // 引數1: 開始下表
                // 引數2: 元素長度,如果不填預設刪除到最後
                // 引數3: 表示使用當前引數替換已經刪除內容的位置
                this.todolist.splice(key, 1);
            },
            up(key) {
                // 向上移動
                // splice(刪除的開始位置,刪除的成員個數, 替換的新資料)
                if (key === 0) {
                    return;
                }
                //就是刪掉然後插入
                ret = this.todolist.splice(key, 1)[0];
                this.todolist.splice(key - 1, 0, ret);
            },
            down(key) {
                // 向下移動
                ret = this.todolist.splice(key, 1)[0];
                this.todolist.splice(key + 1, 0, ret);
            }
        }
    });
</script>
</body>
</html>

4. 通過axios實現資料請求

vue.js預設沒有提供ajax功能的。

所以使用vue的時候,一般都會使用axios的外掛來實現ajax與後端伺服器的資料互動。

注意,axios本質上就是javascript的ajax封裝,所以會被同源策略限制。

外掛: http://www.axios-js.com/

下載地址:

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

axios提供傳送請求的常用方法有兩個:axios.get() 和 axios.post() 。

增 post

刪 delete

改 put/patch

查 get

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>axios</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
    <button @click="get_data">點選</button>
</div>
<script>

    var vm = new Vue({
        el: "#app",
        data: {},
        methods: {
            get_data() {
                // 傳送get請求
                // axios.get('http://baidu.com', {
                //     params: {
                //         //查詢字串的鍵值對
                //         username: 'zbb'
                //     }
                // }, {
                //     //請求頭資訊
                //     Compant: "oldboy"
                // });

                // 傳送post請求
                axios.post("http://www.baidu.com", {
                    username: "xiaoming",
                    password: "123456",
                }, {
                    // 請求頭資訊
                }).then((response) => {
                    // 請求成功以後,axios執行的程式碼
                    // response.data  響應體資料

                }).catch(function (error) {
                    // 請求發生異常錯誤時,axios執行的程式碼
                    // error 錯誤物件(本地)
                    // error.response  來自服務端的響應錯誤資訊
                });

            }
        }
    });

    // 匿名函式
    // var func = function(response){
    // 	// 函式程式碼
    // };
    //
    // // 箭頭函式
    // var func = (response)=>{
    // 	// 函式程式碼
    // }
</script>
</body>
</html>

總結

	// 傳送get請求
    // 引數1: 必填,字串,請求的資料介面的url地址,例如請求地址:http://www.baidu.com?id=200
    // 引數2:可選,json物件,要提供給資料介面的引數
    // 引數3:可選,json物件,請求頭資訊
	// 傳送post請求,引數和使用和axios.get()一樣。
    // 引數1: 必填,字串,請求的資料介面的url地址
    // 引數2:必填,json物件,要提供給資料介面的引數,如果沒有引數,則必須使用{}
    // 引數3:可選,json物件,請求頭資訊

4.1 json

json是 JavaScript Object Notation 的首字母縮寫,單詞的意思是javascript物件表示法,這裡說的json指的是類似於javascript物件的一種資料格式。

json的作用:在不同的系統平臺,或不同程式語言之間傳遞資料。

4.1.1 json資料的語法

json資料物件類似於JavaScript中的物件,但是它的鍵對應的值裡面是沒有函式方法的,值可以是普通變數,不支援undefined,值還可以是陣列或者json物件。

// 原生的js的json物件
var obj = {
  age:10,
  sex: '女',
  work:function(){
    return "好好學習",
  }
}
// json資料的物件格式,json資料格式,是沒有方法的,只有屬性:
{
    "name":"tom",
    "age":18
}

// json資料的陣列格式:
["tom",18,"programmer"]

複雜的json格式資料可以包含物件和陣列的寫法。

{
  "name":"小明",
  "age":200,
  "is_delete": false,
  "fav":["code","eat","swim","read"],
  "son":{
    "name":"小小明",
    "age":100,
    "lve":["code","eat"]
  }
}

// 陣列結構也可以作為json傳輸資料。

json資料可以儲存在.json檔案中,一般裡面就只有一個json物件。

總結:

1. json檔案的字尾是.json
2. json檔案一般儲存一個單一的json資料
3. json資料的屬性不能是方法或者undefined,屬性值只能:數值[整數,小數,布林值]、字串、json和陣列
4. json資料只使用雙引號、每一個屬性成員之間使用逗號隔開,並且最後一個成員沒有逗號。
   {
      "name":"小明",
      "age":200,
      "fav":["code","eat","swim","read"],
      "son":{
        "name":"小小明",
        "age":100
      }
    }

工具:postman可以用於測試開發的資料介面。

4.1.2 js中提供的json資料轉換方法

javascript提供了一個JSON物件來操作json資料的資料轉換.

方法 引數 返回值 描述
stringify json物件 字串 json物件轉成字串
parse 字串 json物件 字串格式的json資料轉成json物件
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>axios</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
	<script>
	var data = {
		"name":"xiaopmiong",
		"age":13,
		"sex":true
	};

	// 把json物件轉換成json字串
	json_str = JSON.stringify(data);
	console.log()

	// 把json字串裝換成json物件
	data_str = '{"name":"xiaopmiong","age":13,"sex":true}';
	json_obj = JSON.parse(data_str);
	console.log(json_obj);
	</script>
</body>
</html>

4.2 ajax

ajax,一般中文稱之為:"阿賈克斯",是英文 “Async Javascript And Xml”的簡寫,譯作:非同步js和xml資料傳輸資料。

ajax的作用: ajax可以讓js代替瀏覽器向後端程式傳送http請求,與後端通訊,在使用者不知道的情況下運算元據和資訊,從而實現頁面區域性重新整理資料/無重新整理更新資料。

所以開發中ajax是很常用的技術,主要用於操作後端提供的資料介面,從而實現網站的前後端分離

ajax技術的原理是例項化js的XMLHttpRequest物件,使用此物件提供的內建方法就可以與後端進行資料通訊。

4.2.1 資料介面

資料介面,也叫api介面,表示後端提供運算元據/功能的url地址給客戶端使用。

客戶端通過發起請求向服務端提供的url地址申請運算元據【操作一般:增刪查改】

同時在工作中,大部分資料介面都不是手寫,而是通過函式庫/框架來生成。

4.2.3 ajax的使用

ajax的使用必須與服務端程式配合使用,但是目前我們先學習ajax的使用,所以暫時先不涉及到服務端python程式碼的編寫。因此,我們可以使用別人寫好的資料介面進行呼叫。

jQuery將ajax封裝成了一個函式$.ajax(),我們可以直接用這個函式來執行ajax請求。

介面 地址
天氣介面 http://wthrcdn.etouch.cn/weather_mini?city=城市名稱
音樂介面搜尋 http://tingapi.ting.baidu.com/v1/restserver/ting?method=baidu.ting.search.catalogSug&query=歌曲標題
音樂資訊介面 http://tingapi.ting.baidu.com/v1/restserver/ting?method=baidu.ting.song.play&songid=音樂ID

編寫程式碼獲取介面提供的資料:

vue版本:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>axios</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
    <button @click="get_data">點選</button>
</div>
<script>
    var vm = new Vue({
        el: "#app",
        data: {},
        methods: {
            get_data() {
                axios.get("http://wthrcdn.etouch.cn/weather_mini?city=北京", {

                }).then(response => {
                    // 成功
                    console.log(response.data);
                }).catch(error => {
                    // 報錯
                    console.log(error.response);
                });
            }
        }
    })

</script>
</body>
</html>

4.2.4 同源策略

同源策略,是瀏覽器為了保護使用者資訊保安的一種安全機制。所謂的同源就是指代通訊的兩個地址(例如服務端介面地址與瀏覽器客戶端頁面地址)之間比較,是否協議、域名(IP)和埠相同。不同源的客戶端指令碼[javascript]在沒有明確授權的情況下,沒有許可權讀寫對方資訊。

ajax本質上還是javascript,是執行在瀏覽器中的指令碼語言,所以會被受到瀏覽器的同源策略所限制。

前端地址:http://www.oldboy.cn/index.html 是否同源 原因
http://www.oldboy.cn/user/login.html 協議、域名、埠相同
http://www.oldboy.cn/about.html 協議、域名、埠相同
https://www.oldboy.cn/user/login.html 協議不同 ( https和http )
http:/www.oldboy.cn:5000/user/login.html 埠 不同( 5000和80)
http://bbs.oldboy.cn/user/login.html 域名不同 ( bbs和www )

同源策略針對ajax的攔截,程式碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="js/vue.js"></script>
    <script src="js/axios.js"></script>
</head>
<body>
    <div id="app">
        <button @click="get_music">點選獲取天氣</button>
    </div>
    <script>
        let vm = new Vue({
            el:"#app",
            data:{},
            methods:{
                get_music(){
                    axios.get("http://tingapi.ting.baidu.com/v1/restserver/ting?method=baidu.ting.search.catalogSug&query=我的中國心")
                        .then(response=>{
                            console.log(response);

                        }).catch(error=>{
                            console.log(error.response)
                    });
                }
            }
        })
    </script>
</body>
</html>

上面程式碼執行錯誤如下:

Access to XMLHttpRequest at 'http://tingapi.ting.baidu.com/v1/restserver/ting?method=baidu.ting.search.catalogSug&query=%E6%88%91%E7%9A%84%E4%B8%AD%E5%9B%BD%E5%BF%83' from origin 'http://localhost:63342' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

上面錯誤,關鍵詞:Access-Control-Allow-Origin

只要出現這個關鍵詞,就是訪問受限。出現同源策略的攔截問題。

4.2.5 ajax跨域(跨源)方案之CORS

ajax跨域(跨源)方案:後端授權[CORS],jsonp,服務端代理

  CORS是一個W3C標準,全稱是"跨域資源共享",它允許瀏覽器向跨源的後端伺服器發出ajax請求,從而克服了AJAX只能同源使用的限制。

  實現CORS主要依靠<mark>後端伺服器中響應資料中設定響應頭資訊Access-Control-Allow-Origin返回</mark>的。

django的檢視

def post(request):

response = new Response()

response .headers["Access-Control-Allow-Origin"] = "http://localhost:63342"

return response;
// 在響應行資訊裡面設定以下內容:
Access-Control-Allow-Origin: ajax所在的域名地址

Access-Control-Allow-Origin: www.oldboy.cn  # 表示只允許www.oldboy.cn域名的客戶端的ajax跨域訪問

// * 表示任意源,表示允許任意源下的客戶端的ajax都可以訪問當前服務端資訊
Access-Control-Allow-Origin: *

總結:

0. 同源策略:瀏覽器的一種保護使用者資料的一種安全機制。
   瀏覽器會限制ajax不能跨源訪問其他源的資料地址。
   同源:判斷兩個通訊的地址之間,是否協議,域名[IP],埠一致。
   
   ajax:  http://127.0.0.1/index.html
   api資料介面:  http://localhost/index
   
   這兩個是同源麼?不是同源的。是否同源的判斷依據不會根據電腦來判斷,而是通過協議、域名、埠的字串是否來判斷。
   
1. ajax預設情況下會受到同源策略的影響,一旦受到影響會報錯誤如下:
	 No 'Access-Control-Allow-Origin' header is present on the requested resource

2. 解決ajax只能同源訪問資料介面的方式:
   1. CORS,跨域資源共享,在服務端的響應行中設定:
      Access-Control-Allow-Origin: 允許訪問的域名地址
   2. jsonp
   3. 是否服務端代理
      思路:通過python來請求對應的伺服器介面,獲取到資料以後,

jsonp方法

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>jsonp</title>
	<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
</head>
<body>
	<button>點選</button>
	<script>
		// function get_data(){
		// 	// 傳送請求
		// 	// 1. 建立一個支援跨域標籤的標籤[script]
		// 	var script = document.createElement("script");
		// 	// 2. 給標籤加上src屬性,指向請求的地址
		// 	script.src="http://tingapi.ting.baidu.com/v1/restserver/ting?method=baidu.ting.search.catalogSug&query=我的中國心"
		// 	console.log(script);
		// 	// 3. 把設定好的script標籤放到head標籤裡面
		// 	document.head.appendChild(script);
		// 	// 4. 呼叫伺服器返回的資料,提前宣告一個函式,返回的資料作為引數
		//
		// }
		// // callback(`{"song":[{"bitrate_fee":"{\\"0\\":\\"0|0\\",\\"1\\":\\"0|0\\"}","weight":"13099","songname":"我的中國心","resource_type":"0","songid":"604603771","has_mv":"0","yyr_artist":"0","resource_type_ext":"0","artistname":"CBS","info":"","resource_provider":"1","control":"0000000000","encrypted_songid":"78082409857A085D08CADC"},{"bitrate_fee":"{\\"0\\":\\"129|-1\\",\\"1\\":\\"-1|-1\\"}","weight":"4199","songname":"月亮代表我的中國心","resource_type":"0","songid":"544880401","has_mv":"0","yyr_artist":"0","resource_type_ext":"2","artistname":"大慶小芳","info":"","resource_provider":"1","control":"0000000000","encrypted_songid":"3408207A37080859645F87"}],"order":"song,album","error_code":22000,"album":[{"albumname":"我的中國心","weight":"130","artistname":"CBS","resource_type_ext":"0","artistpic":"http:\\/\\/qukufile2.qianqian.com\\/data2\\/pic\\/3b22a5976d07dbbe38b60f92ab2b6afd\\/660129785\\/660129785.jpg@s_2,w_40,h_40","albumid":"604603768"},{"albumname":"我的中國心","weight":"0","artistname":"陳東東","resource_type_ext":"0","artistpic":"http:\\/\\/qukufile2.qianqian.com\\/data2\\/pic\\/default_album.jpg@s_2,w_40,h_40","albumid":"611655247"}]}`)
		// function callback(data){
		// 	console.log(data);
		// }

		$.ajax({
			url:"http://tingapi.ting.baidu.com/v1/restserver/ting?method=baidu.ting.search.catalogSug&query=我的中國心",
			type:"get",
			dataType:"jsonp"
		}).then(response=>{
			console.log(response);
		});

	</script>
</body>
</html>

5. 元件化開發

5.1 元件[component]

元件(Component)是自定義封裝的功能。在前端開發過程中,經常出現多個網頁的功能是重複的,而且很多不同的頁面之間,也存在同樣的功能。

而在網頁中實現一個功能,需要使用html定義功能的內容結構,使用css宣告功能的外觀樣式,還要使用js來定義功能的特效,因此就產生了把一個功能相關的[HTML、css和javascript]程式碼封裝在一起組成一個整體的程式碼塊封裝模式,我們稱之為“元件”。

所以,元件就是一個html網頁中的功能,一般就是一個標籤,標籤中有自己的html內容結構,css樣式和js特效。

這樣,前端人員就可以在元件化開發時,只需要書寫一次程式碼,隨處引入即可使用。

vue的元件有兩種:預設元件[全域性元件] 和 單檔案元件

5.1.1 預設元件(很少用)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>zbb</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="page">
    <!--    元件名aa 寫好之後直接執行元件名即可-->
    <aa></aa>
    <aa></aa>
</div>
<script>
    Vue.component("aa", {
        template: "<p>公共元件<span @click='show'>{{message}}</span></p>",
        // data在元件中變成了一個函式,函式的返回值必須是一個json物件
        data: function () {
            return {
                message: "這是一本書"
            }
        },
        methods: {
            show() {
                alert(this.message)
            }
        }

    })
    var vm = new Vue({
        el: '#page',
        data: {},
    })
</script>
</body>
</html>

6. Vue自動化工具(Vue-cli)

前面學習了普通元件以後,接下來我們繼續學習單檔案元件則需要提前先安裝準備一些元件開發工具。否則無法使用和學習單檔案元件。

一般情況下,單檔案元件,我們執行在 自動化工具vue-CLI中,可以幫我們編譯單檔案元件。所以我們需要在系統中先搭建vue-CLI工具,

官網:https://cli.vuejs.org/zh/

Vue CLI 需要 Node.js 8.9 或更高版本 (推薦 8.11.0+)。你可以使用 nvmnvm-windows在同一臺電腦中管理多個 Node 版本。

nvm工具的下載和安裝: https://www.jianshu.com/p/d0e0935b150a

https://www.jianshu.com/p/622ad36ee020

安裝記錄:

開啟:https://github.com/coreybutler/nvm-windows/releases 下載然後安裝

常用的nvm命令

nvm list                   # 列出目前在nvm裡面安裝的所有node版本
nvm install node版本號      # 安裝指定版本的node.js
nvm uninstall node版本號    # 解除安裝指定版本的node.js
nvm use node版本號          # 切換當前使用的node.js版本	

如果使用nvm工具,則直接可以不用自己手動下載,如果使用nvm下載安裝 node的npm比較慢的時候,可以修改nvm的配置檔案(在安裝根目錄下)

#settings.txt
root: C:\tool\nvm    [這裡的目錄地址是安裝nvm時自己設定的地址,要根據實際修改]
path: C:\tool\nodejs
arch: 64
proxy: none
node_mirror: http://npm.taobao.org/mirrors/node/ 
npm_mirror: https://npm.taobao.org/mirrors/npm/

6.1 安裝node.js

Node.js是一個新的後端(後臺)語言,它的語法和JavaScript類似,所以可以說它是屬於前端的後端語言,後端語言和前端語言的區別:

  • 執行環境:後端語言一般執行在伺服器端,前端語言執行在客戶端的瀏覽器上
  • 功能:後端語言可以操作檔案,可以讀寫資料庫,前端語言不能操作檔案,不能讀寫資料庫。

我們一般安裝LTS(長線支援版本 Long-Time Support):

下載地址:https://nodejs.org/en/download/【上面已經安裝了nvm,那麼這裡不用手動安裝了】

node.js的版本有兩大分支:

官方釋出的node.js版本:0.xx.xx 這種版本號就是官方釋出的版本

社群釋出的node.js版本:xx.xx.x 就是社群開發的版本

Node.js如果安裝成功,可以檢視Node.js的版本,在終端輸入如下命令:

node -v

6.2 npm

在安裝node.js完成後,在node.js中會同時幫我們安裝一個npm包管理器npm。我們可以藉助npm命令來安裝node.js的包。這個工具相當於python的pip管理器。

npm install -g 包名              # 安裝模組   -g表示全域性安裝,如果沒有-g,則表示在當前專案安裝
npm list                        # 檢視當前目錄下已安裝的node包
npm view 包名 engines            # 檢視包所依賴的Node的版本 
npm outdated                    # 檢查包是否已經過時,命令會列出所有已過時的包
npm update 包名                  # 更新node包
npm uninstall 包名               # 解除安裝node包
npm 命令 -h                      # 檢視指定命令的幫助文件

6.3 安裝Vue-cli

npm install -g vue-cli

如果安裝速度過慢,一直超時,可以考慮切換npm映象源:http://npm.taobao.org/

6.4 使用Vue-CLI初始化建立前端專案

6.4.1 生成專案目錄

使用vue自動化工具可以快速搭建單頁應用專案目錄。

該工具為現代化的前端開發工作流提供了開箱即用的構建配置。只需幾分鐘即可建立並啟動一個帶熱過載、儲存時靜態檢查以及可用於生產環境的構建配置的專案:

#生成一個基於 webpack 模板的新專案
vue init webpack 專案目錄名

例如:
vue init webpack myproject

// 啟動開發伺服器 ctrl+c 停止服務
cd myproject
npm run dev           # 執行這個命令就可以啟動node提供的測試http伺服器

執行了上面程式碼以後,終端下會出現以下效果提示:

那麼訪問:http://localhost:8080/

6.4.2 專案目錄結構

src 主開發目錄,要開發的單檔案元件全部在這個目錄下的components目錄下

static 靜態資源目錄,所有的css,js檔案放在這個資料夾

dist專案打包釋出資料夾,最後要上線單檔案專案檔案都在這個資料夾中[後面打包專案,讓專案中的vue元件經過編譯變成js 程式碼以後,dist就出現了]

node_modules目錄是node的包目錄,

config是配置目錄,

build是專案打包時依賴的目錄

src/router 路由,後面需要我們在使用Router路由的時候,自己宣告.

6.4.3 專案執行流程圖

整個專案是一個主檔案index.html,index.html中會引入src資料夾中的main.js,

main.js中會匯入頂級單檔案元件App.vue,

App.vue中會通過元件巢狀或者路由來引用components資料夾中的其他單檔案元件。

7. 單檔案元件的使用

元件有兩種:普通元件、單檔案元件

普通元件的缺點:

  1. html程式碼是作為js的字串進行編寫,所以組裝和開發的時候不易理解,而且沒有高亮效果。
  2. 普通元件用在小專案中非常合適,但是複雜的大專案中,如果把更多的元件放在html檔案中,那麼維護成本就會變得非常昂貴。
  3. 普通元件只是整合了js和html,但是css程式碼被剝離出去了。使用的時候的時候不好處理。

將一個元件相關的html結構,css樣式,以及互動的JavaScript程式碼從html檔案中剝離出來,合成一個檔案,這種檔案就是單檔案元件,相當於一個元件具有了結構、表現和行為的完整功能,方便元件之間隨意組合以及元件的重用,這種檔案的副檔名為“.vue”,比如:"Home.vue"。

在元件中編輯三個標籤,編寫檢視、vm物件和css樣式程式碼。

7.1 完成案例-點選加減數字

建立Home.vue

<template>
  <div>
    <button @click="add">+</button>
    <input type="text" v-model="num">
    <button @click="sub">-</button>
  </div>
</template>

<script>
  export default {
    name: "Home",//元件名,提供給路由,進行頁面渲染
    data() {
      return {
        num: 0,
      }
    },
    methods: {
      add() {
        this.num = parseInt(this.num) + 1;
      },
      sub() {
        if (this.num <= 1) {
          return 0;
        } else {
          this.num -= 1;
        }
      }
    }
  }
</script>

<style scoped>
  /*空間*/
  input[type=text] {
    width: 400px;
  }
</style>

在App.vue元件中呼叫上面的元件

<template>
  <div id="app">
    <Home></Home>
  </div>
</template>

<script>
  import Home from "./components/Home";

  export default {
    name: 'App',
    components: {
      Home
    }
  }
</script>

<style>

</style>

在開發vue專案之前,需要手動把 App.vue的HelloWorld元件程式碼以及預設的css樣式,清除

7.2 元件的巢狀

有時候開發vue專案時,頁面也可以算是一個大元件,同時頁面也可以分成多個子元件.

因為,產生了父元件呼叫子元件的情況.

例如,我們可以宣告一個元件,作為父元件

在components/建立一個子元件,例如,是Menu.vue

<template>
  <div class="menu">
    <ul>
      <li v-for="i in list">{{i}}</li>
    </ul>
  </div>
</template>

<script>
  export default {
    name: "Menu",
    data() {
      return {
        list: [
          "首頁",
          "列表",
          "詳情"
        ],
      }
    }
  }
</script>

<style scoped>
ul{
  list-style: none;
  margin: 0;
  padding: 0;
}
</style>

然後,在父元件中呼叫上面宣告的子元件。

Home.vue

<template>
  <div>
    <Menu></Menu>
    <button @click="add">+</button>
    <input type="text" v-model="num">
    <button @click="sub">-</button>
  </div>
</template>

<script>
  import Menu from "./Menu";

  export default {
    name: "Home",
    components: {Menu},
//元件名,提供給路由,進行頁面渲染

    data() {
      return {
        num: 0,
      }
    },
    methods: {
      add() {
        this.num = parseInt(this.num) + 1;
      },
      sub() {
        if (this.num <= 1) {
          return 0;
        } else {
          this.num -= 1;
        }
      }
    },
    comments: {
      Menu
    }
  }
</script>

<style scoped>
  /*空間*/
  input[type=text] {
    width: 40px;
  }
</style>

最後,父元件被App.vue呼叫.就可以看到頁面效果.

<template>
  <div id="app">
    <Home></Home>
  </div>
</template>

<script>
  import Home from "./components/Home";
  export default {
    name: 'App',
    components: {
      Home
    }
  }
</script>
<style>
</style>

7.3 傳遞資料

父元件的資料傳遞給子元件

例如,我們希望把父元件的資料傳遞給子元件.

可以通過props屬性來進行資料傳遞.

傳遞資料三個步驟:

  1. 在父元件中,呼叫子元件的元件標籤時,使用屬性值的方式往下傳遞資料

    <template>
      <div>
        <Menu msg="傳遞的資料" :mynum="num"></Menu>
        <button @click="add">+</button>
        <input type="text" v-model="num">
        <button @click="sub">-</button>
      </div>
    </template>
    

    .上面表示在父元件呼叫Menu子元件的時候傳遞了2個資料:
    .如果要傳遞變數,屬性名左邊必須加上冒號:,同時,屬性名是自定義的,會在子元件中使用。
    .如果要傳遞普通字串資料,則不需要加上冒號:

  2. 在子元件中接受上面父元件傳遞的資料,需要在vm元件物件中,使用props屬性類接受。

    <script>
      export default {
        name: "Menu",
        props:["msg","mynum"],
        data() {
          return {
            list: [
              "首頁",
              "列表",
              "詳情"
            ],
          }
        }
      }
    </script>
    // 上面 props屬性中表示接受了兩個資料。
    
  3. 在子元件中的template中使用父元件傳遞過來的資料.

    <template>
      <div class="menu">
        <h1>{{msg}}</h1>
        <h1>{{mynum}}</h1>
        <ul>
          <li v-for="i in list">{{i}}</li>
        </ul>
      </div>
    </template>
    

使用父元件傳遞資料給子元件時, 注意一下幾點:

  1. 傳遞資料是變數,則需要在屬性左邊新增冒號.

    傳遞資料是變數,這種資料稱之為"動態資料傳遞"

    傳遞資料不是變數,這種資料稱之為"靜態資料傳遞"

  2. 父元件中修改了資料,在子元件中會被同步修改,但是,子元件中的資料修改了,是不是影響到父元件中的資料.

    這種情況,在開發時,也被稱為"單向資料流"

子元件傳遞資料給父元件

  1. 在子元件中,通過this.$emit()來呼叫父元件中定義的事件.

    <template>
      <div class="menu">
        <h1>{{msg}}</h1>
        <h1>{{mynum}}</h1>
        <input type="text" v-model="mynum">
        <ul>
          <li v-for="i in list">{{i}}</li>
        </ul>
      </div>
    </template>
    
    <script>
      export default {
        name: "Menu",
        props: ["msg", "mynum"],
        data() {
          return {
            list: [
              "首頁",
              "列表",
              "詳情"
            ],
          }
        },
        //這裡傳值
        watch: {
          mynum() {
            this.$emit("zz",this.mynum)
          }
        }
      }
    </script>
    
    <style scoped>
      ul {
        list-style: none;
        margin: 0;
        padding: 0;
      }
    </style>
    
    
  2. 父元件中宣告一個和子元件中this.$emit("自定義事件名稱")對應的事件屬性。

    <template>
      <div>
        <Menu msg="傳遞的資料" :mynum="num" @zz="zz"></Menu>
        <button @click="add">+</button>
        <input type="text" v-model="num">
        <button @click="sub">-</button>
      </div>
    </template>
    
  3. 父元件中,宣告一個自定義方法,在事件被呼叫時,執行的。

    <script>
      import Menu from "./Menu";
    
      export default {
        name: "Home",
        components: {Menu},
    //元件名,提供給路由,進行頁面渲染
    
        data() {
          return {
            num: 0,
          }
        },
        methods: {
          add() {
            this.num = parseInt(this.num) + 1;
          },
          sub() {
            if (this.num <= 1) {
              return 0;
            } else {
           this.num -= 1;
            }
          },
          zz(data) {
            console.log("父元件繫結的方法");
            this.num=data
          }
        },
        comments: {
          Menu
        }
      }
    </script>
    
    <style scoped>
      /*空間*/
      input[type=text] {
        width: 40px;
      }
    </style>
    
    

8. 在元件中使用axios獲取資料

預設情況下,我們的專案中並沒有對axios包的支援,所以我們需要下載安裝。

在專案根目錄中使用 npm安裝包

npm install axios

接著在main.js檔案中,匯入axios並把axios物件 掛載到vue屬性中作為一個子物件,這樣我們才能在元件中使用。

import Vue from 'vue' // 這裡表示從別的目錄下匯入 單檔案元件
import App from './App' // 從node_modules目錄中匯入包
import axios from 'axios' // 把物件掛載vue中

Vue.config.productionTip = false
Vue.prototype.$axios = axios; // 把物件掛載vue中
new Vue({
  el: '#app',
  components: { App },
  template: '<App/>'
})

8.1 在組建中使用axios獲取資料

<script>
  export default{
	methods:{
         // 使用axios請求資料
      get_w() {
        this.$axios.get("http://wthrcdn.etouch.cn/weather_mini?city=青島").then((response) => {
          console.log(response.data);

        })
      }
    },
</script>

效果:

使用的時候,因為本質上來說,我們還是原來的axios,所以也會收到同源策略的影響。

9.查詢未來5天的天氣

單檔案

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
    <div id="app">
        <input type="text" v-model="city" placeholder="請填寫查詢的城市" id="">
        <button @click="get_weather">檢視天氣</button>
        <table border="1" width="600">
            <tr>
                <td colspan="4">今天天氣情況: {{weather_info}}</td>
            </tr>
            <tr>
                <th>日期</th>
                <th>風力</th>
                <th>溫度</th>
                <th>狀況</th>
            </tr>
            <tr v-for="item in date_list">
                <td>{{item.date}}</td>
                <td>{{item.fengli|sub_cdata}}</td>
                <td>{{item.low}}~{{item.high}}</td>
                <td>{{item.type}}</td>
            </tr>
        </table>
    </div>
    <script>
        var vm = new Vue({
            el:"#app",
            data:{
                city: "",
                weather_info:"",
                date_list:[],
            },
            filters:{
                sub_cdata(data){
                    data = data.replace("<![CDATA[","");
                    data = data.replace("]]>","");
                    return data;
                }
            },
            methods:{
                get_weather(){
                    axios.get("http://wthrcdn.etouch.cn/weather_mini",{
                        params:{
                            city:this.city,
                        }
                    }).then(response=>{
                        console.log(response.data);
                        this.weather_info = response.data.data.ganmao;
                        this.date_list = response.data.data.forecast;
                    }).catch(error=>{
                        console.log(error);
                    })
                }
            }
        })
    </script>
</body>
</html>

元件

App.vue

<template>
  <div id="app">
    <Tiqian></Tiqian>
  </div>
</template>

<script>
import Tiqian from "./components/Tiqian";
  export default {
    name: 'App',
    components: {
      Tiqian
    }
  }
</script>

<style>

</style>

Tiqian

<template>
  <div>
    <input type="text" v-model="city" placeholder="請填寫查詢的城市" id="">
    <button @click="get_weather">檢視天氣</button>
    <table border="1" width="600">
      <tr>
        <td colspan="4">今天天氣情況: {{weather_info}}</td>
      </tr>
      <tr>
        <th>日期</th>
        <th>風力</th>
        <th>溫度</th>
        <th>狀況</th>
      </tr>
      <tr v-for="item in date_list">
        <td>{{item.date}}</td>
        <td>{{item.fengli|sub_cdata}}</td>
        <td>{{item.low}}~{{item.high}}</td>
        <td>{{item.type}}</td>
      </tr>
    </table>
  </div>
</template>

<script>
  export default {
    name: "tiqian",
    data() {
      return {
        city: "",
        weather_info: "",
        date_list: [],
      }
    },
    filters: {
      sub_cdata(data) {
        data = data.replace("<![CDATA[", "");
        data = data.replace("]]>", "");
        return data;
      }
    },
    methods: {
      get_weather() {
        this.$axios.get("http://wthrcdn.etouch.cn/weather_mini", {
          params: {
            city: this.city,
          }
        }).then(response => {
          console.log(response.data);
          this.weather_info = response.data.data.ganmao;
          this.date_list = response.data.data.forecast;
        }).catch(error => {
          console.log(error);
        })
      }
    }
  }
</script>;
<style scoped>
</style>

1. 專案分析

首頁
	導航、登入註冊欄、輪播圖、底部導航

2. 專案搭建

2.1 建立專案目錄

cd 專案目錄
vue init webpack luffycity

除了code test,test2其他都選擇

接下來,我們根據終端上效果顯示的對應地址來訪問專案(如果有多個vue專案在執行,8080埠被佔據了,伺服器會自動改埠,所以根據自己實際在操作中看到的地址來訪問。)

訪問:http://localost:8080

2.2 初始化專案

清除預設的HelloWorld.vue元件和APP.vue中的預設模板程式碼和預設樣式

<template>
  <div id="app">
    <router-view/>
  </div>
</template>

<script>
export default {
  name: 'App'
}
</script>
<style>
</style>

2.3.2 配置路由

2.3.2.1 初始化路由物件

在src目錄下的router目錄下修改index.js路由檔案

index.js路由檔案中,編寫初始化路由物件的程式碼 .

import Vue from 'vue'
import Router from 'vue-router'
// import HelloWorld from '@/components/HelloWorld'
// 這裡匯入可以讓讓使用者訪問的元件
Vue.use(Router)

export default new Router({
  // 設定路由模式為‘history’,去掉預設的#
  mode: "history",
  routes: [
    {
      // path: '/',
      // name: 'HelloWorld'  路由別名
      // component: HelloWorld 元件類名
    }
  ]
})

接下來,我們可以檢視效果了,一張白紙~

3. 引入ElementUI

對於前端頁面佈局,我們可以使用一些開源的UI框架來配合開發,Vue開發前端專案中,比較常用的就是ElementUI了。

ElementUI是餓了麼團隊開發的一個UI元件框架,這個框架提前幫我們提供了很多已經寫好的通用模組,我們可以在Vue專案中引入來使用,這個框架的使用類似於我們前面學習的bootstrap框架,也就是說,我們完全可以把官方文件中的元件程式碼拿來就用,有定製性的內容,可以直接通過樣式進行覆蓋修改就可以了。

https://element.eleme.cn/

3.1 快速安裝ElementUI

專案根目錄執行以下命令:

npm i element-ui -S

上面的命令等同於 npm install element-ui --save

3.2 配置ElementUI到專案中

在main.js中匯入ElementUI,並呼叫。程式碼:

// 匯入 elementUI的元件庫
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';

// 呼叫外掛
Vue.use(ElementUI);

或者在index中新增

在index.html入口檔案中,載入樣式庫,程式碼:

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <!-- i	mport CSS -->
  <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
</head>
<body>
  <div id="app">
    <el-button @click="visible = true">Button</el-button>
    <el-dialog :visible.sync="visible" title="Hello world">
      <p>Try Element</p>
    </el-dialog>
  </div>
</body>
  <!-- import Vue before Element -->
  <script src="https://unpkg.com/vue/dist/vue.js"></script>
  <!-- import JavaScript -->
  <script src="https://unpkg.com/element-ui/lib/index.js"></script>
  <script>
    new Vue({
      el: '#app',
      data: function() {
        return { visible: false }
      }
    })
  </script>
</html>

成功引入了ElementUI以後,接下來我們就可以開始進入前端頁面開發,首先是首頁。

4. 首頁

首頁採用了上下頁面佈局,首頁是導航欄、輪播圖。。。腳部等幾個小模組。所以我們可以把首頁作為一個元件進行開發,然後把首頁的這些小模組作為單獨的元件來進行開發。

4.1 建立首頁元件

在src/components目錄下建立檔案 Home.vue

程式碼:

<template>
  <div class="home">首頁</div>
</template>

<script>
  export default {
    name: "Home"
  }
</script>

<style scoped>

</style>

4.1.1 建立首頁對應的路由

在router/index.js中引入Home元件,並設定Home元件作為首頁路由。

程式碼:

import Vue from 'vue'
import Router from 'vue-router'
import Home from "../components/Home";
// 這裡匯入可以讓讓使用者訪問的元件
Vue.use(Router)

export default new Router({
  // 設定路由模式為‘history’,去掉預設的#
  mode: "history",
  routes: [
    {
      path: '/',
      name: 'Home' ,
      component: Home
    }
  ]
})

4.2 開發頭部子元件

經過前面的觀察,可以發現導航不僅在首頁出現,其他頁面也有,所以對於這些不同頁面中公共的內容,可以建立一個單獨的元件目錄存放。

建立Header.vue目錄路徑,編寫程式碼:

<template>
  <div>頭部</div>
</template>

<script>
  export default {
    name: "Header"
  }
</script>

<style scoped>

</style>

4.2.1 在首頁引入導航元件

程式碼:home.vue

<template>
  <div class="home">首頁
    <Header></Header>
  </div>
</template>

<script>
  import Header from "./common/Header";

  export default {
    name: "Home",
    data() {
      return {};
    },
    components: {
      Header
    }
  }
</script>

<style scoped>

</style>

接下來,我們就可以在元件中參考ElementUI文件來進行樣式開發了。

初始化樣式

@charset "utf-8";
/* 宣告全域性樣式和專案的初始化樣式 */
body,h1,h2,h3,h4,p,table,tr,td,ul,li,a,form,input,select,option,textarea{
  margin:0;
  padding: 0;
  font-size: 15px;
}
a{
  text-decoration: none;
  color: #333;
}
ul,li{
  list-style: none;
}
table{
  border-collapse: collapse; /* 合併邊框 */
}
img{
    max-width: 100%;
    max-height: 100%;
}
/* 工具的全域性樣式 */
.full-left{
  float: left!important;
}
.full-right{
  float: right!important;
}

[class*=" el-icon-"], [class^=el-icon-]{
  font-size: 50px;
}
.el-carousel__arrow{
  width: 80px;
  height: 80px;
}
.el-checkbox__input.is-checked .el-checkbox__inner,
.el-checkbox__input.is-indeterminate .el-checkbox__inner{
  background: #ffc210;
  border-color: #ffc210;
  border: none;
}
.el-checkbox__inner:hover{
  border-color: #9b9b9b;
}
.el-checkbox__inner{
  width: 16px;
  height: 16px;
  border: 1px solid #9b9b9b;
  border-radius: 0;
}
.el-checkbox__inner::after{
  height: 9px;
  width: 5px;
}

在main.js中引入 初始化css

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from "./router/index"

Vue.config.productionTip = false;

// elementUI 匯入
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
// 呼叫外掛
Vue.use(ElementUI);
// 載入初始化樣式
import "../static/css/reset.css";

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})

Header的子元件程式碼:

<template>
  <div class="header-box">
    <div class="header">
      <el-row>
        <el-col :span="4" class="logo">
          <a href=""><img src="/static/images/logo.svg" alt=""></a>
        </el-col>
        <el-col :span="15">
          <el-menu class="nav" mode="horizontal">
            <el-menu-item>免費課</el-menu-item>
            <el-menu-item>實戰課</el-menu-item>
            <el-menu-item>老男孩教育</el-menu-item>
          </el-menu>

        </el-col>
        <el-col :span="5" class="header-right">
          <a href="" class="cart">
            <img src="/static/images/cart.svg" alt="">
            購物車
          </a>
          <div class="loginbar">
            <a href="" class="login">登入</a>
            &nbsp;|&nbsp;
            <a href="" class="register">註冊</a>
          </div>
        </el-col>
      </el-row>
    </div>
  </div>
</template>

<script>
export default {
  name:"Header",
  data(){
    return {

    }
  }
}
</script>

<style scoped>
  .header-box{
    height: 80px;
  }
  .header{
    box-shadow: 0 0.5px 0.5px 0 #c9c9c9;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    margin: auto;
    z-index: 99;
    background: #fff;
  }
  .logo{
    height: 80px;
    line-height: 80px;
  }
  .logo a{
    display: block;
    overflow: hidden;
    height: 80px;
    line-height: 80px;
    text-align: center;
  }
  .logo a img{
    vertical-align: middle;
  }
  .nav{
    height: 80px;
  }
  .el-menu--horizontal>.el-menu-item{
    height: 80px;
    line-height: 80px;
  }
  .header .nav li{
    color: #4a4a4a;
  }
  .header .nav li:hover{
    color: #000;
  }
  .header .header-right{
    height: 80px;
    line-height: 80px;
  }
  .header .header-right .cart{
    float:left;
    margin-right: 20px;
    height: 28px;
    width: 88px;
    margin-top: 26px;
    line-height: 28px;
  }
  .header .header-right .cart:hover{
    background: #f0f0f0;
    border-radius: 17px;
  }
  .header .header-right .cart img{
    width: 15px;
    margin-right: 4px;
    margin-left: 6px;
  }
  .header .header-right .loginbar{
    float: left;
  }
  .header .header-right .loginbar a:hover{
    color: #000;
  }
</style>

4.3 開發輪播圖子元件

4.3.1 建立Banner.vue元件檔案

程式碼:

<template>
  <div class="banner">

  </div>
</template>

<script>
  export default {
    name:"Banner",
    data(){
      return {};
    }
  }
</script>

<style scoped>

</style>

4.3.1 在Home元件中引入Banner子元件

<template>
  <div class="home">
    <Header/>
    <Banner/>
  </div>
</template>

<script>
  import Header from "./common/Header"
  import Banner from "./common/Banner"
  export default{
    name:"Home",
    data(){
      return {};
    },
    components:{
      Header,
      Banner,
    }
  }
</script>

<style scoped>
</style>

接下來,在ElementUI中有對應的輪播圖[跑馬燈]效果,可以直接提取過來使用。

注意,圖片儲存到static目錄下。儲存在assets目錄下的圖片等同於儲存在static/images目錄下。

對於圖片的使用,如果是vue程式碼中直接要使用的圖片,可以儲存accets目錄下,如果是第三方外掛要使用到的圖片,需要儲存在static目錄下。其實本質上來說,所有的圖片都是儲存在static目錄下的,而assets目錄下的內容,最終被vue解析成地址的時候,也是在static目錄的.

Banner.vue元件,程式碼:

<template>
  <div class="banner">
      <el-carousel height="506px">
        <el-carousel-item v-for="banner in banner_list" :key="banner">
          <a :href="banner.link"><img width="100%" :src="banner.img" alt=""></a>
        </el-carousel-item>
      </el-carousel>
  </div>
</template>

<script>
  export default {
    name:"Banner",
    data(){
      return {
        banner_list:[
          {link:"http://www.baidu.com",img:"/static/images/banner1.png"},
          {link:"http://www.baidu.com",img:"/static/images/banner2.png"},
        ]
      };
    }
  }
</script>

<style scoped>

</style>

4.5 頁面腳部

4.5.1 建立腳部元件檔案

程式碼:

<template>
  <el-container>

  </el-container>
</template>

<script>
  export default {
    name:"Footer",
    data(){
      return {}
    }
  }
</script>


<style scoped>

</style>

4.5.2 在Home元件中引入Footer元件

Home元件程式碼:

<template>
  <div class="home">
    <Header/>
    <Banner/>
    <Footer/>
  </div>
</template>

<script>
  import Header from "./common/Header"
  import Banner from "./common/Banner"
  import Footer from "./common/Footer"
  export default{
    name:"Home",
    data(){
      return {};
    },
    components:{
      Header,
      Banner,
      Footer,
    }
  }
</script>

<style scoped>

</style>

4.5.3 編寫腳部樣式

<template>
  <div class="footer">
    <el-container>
      <el-row>
        <el-col :span="4">
          <router-link to="">關於我們</router-link>
        </el-col>
        <el-col :span="4">
          <router-link to="">聯絡我們</router-link>
        </el-col>
        <el-col :span="4">
          <router-link to="">商務合作</router-link>
        </el-col>
        <el-col :span="4">
          <router-link to="">幫助中心</router-link>
        </el-col>
        <el-col :span="4">
          <router-link to="">意見反饋</router-link>
        </el-col>
        <el-col :span="4">
          <router-link to="">新手指南</router-link>
        </el-col>
        <el-col :span="24"><p class="copyright">Copyright © sadasdsy.com版權所有 | 京ICP備17072161號-1</p></el-col>
      </el-row>
    </el-container>
  </div>
</template>

<script>
  export default {
    name: "Footer",
    data() {
      return {}
    }
  }
</script>


<style scoped>
  .footer {
    width: 100%;
    height: 128px;
    background: #25292e;
  }

  .footer .el-container {
    width: 1200px;
    margin: auto;
  }

  .footer .el-row {
    align-items: center;
    padding: 0 200px;
    padding-bottom: 15px;
    width: 100%;
    margin-top: 38px;
  }

  .footer .el-row a {
    color: #fff;
    font-size: 14px;
  }

  .footer .el-row .copyright {
    text-align: center;
    color: #fff;
    font-size: 14px;
  }
</style>

相關文章