1. 程式人生 > 其它 >Vue 基礎學習筆記

Vue 基礎學習筆記

1 Vue 簡介

1.1 什麼是 Vue
  • Vue 是一套用於構建使用者介面的漸進式框架

  • Vue 被設計為可以自底向上逐層應用

  • Vue 的核心庫只關注檢視層,不僅易於上手,還便於與第三方庫或既有專案整合

  • 當與現代化的工具鏈以及各種支援類庫結合使用時,Vue 也完全能夠為複雜的單頁應用提供驅動

1.2 第一個 Vue 程式
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>

<div id="app">{{message}}</div>

<script src="../statics/vue.js"></script>
<script>
    let vm = new Vue({
        el: '#app',			<!--使用 id 選擇器繫結 div 元素-->
        data: {
            message: 'Hello Vue!'
        }
    });
</script>
</body>
</html>
1.3 MVVM 模式
  • MVVM 全稱 Model-View-ViewNodel,是一種軟體架構設計,是一種簡化使用者介面的事件驅動程式設計方式

  • MVVM 模式與 MVC 一樣,目的都是為了分離檢視和模型

  • 它具有低耦合、可複用、獨立開發、可測試幾大特點

2 基本語法

在 Vue 中,所有的 v- 開頭的東西都稱之為指令,它會在渲染的 DOM 上應用特殊的響應行為

2.1 v-bind

v-bind 表示將該元素結點的某屬性與 Vue 的某屬性保持一致

<!--表示將 id=app 的 div 元素的 title 屬性,與 Vue 的 message 屬性保持一致-->
<div id = "app" v-bind:title="message">滑鼠懸停檢視資訊</div>

<script>
    let vm = new Vue({
        el: '#app',
        data: {
            message: 'Hello'
        }
    });
</script>
2.2 v-if、v-else

很顯然,就是流程控制中的判斷

<div id="app">
    <div v-if="msg">Yes</div>
    <div v-else>No</div>
</div>

<script>
    let vm = new Vue({
        el: '#app',
        data: {
            msg: true
        }
    });
</script>
2.3 v-if-else
<div id="app">
    <div v-if="msg==='A'">A</div>
    <div v-else-if="msg==='B'">B</div>
    <div v-else>C</div>
</div>

<script>
    let vm = new Vue({
        el: '#app',
        data: {
            msg: 'B'
        }
    });
</script>
2.4 v-for

流程控制中的迴圈

<div id="app">
    <p v-for="(item, index) in items">
        {{item.msg}} ==> {{index}}
    </p>
</div>

<script>
    let vm = new Vue({
        el: '#app',
        data: {
            arrays: [
                {user: '荒天帝'},
                {user: '林楓'},
                {user: '石昊'}
            ]
        }
    });
</script>

3 繫結事件

<div id="app">
    <button v-on:click="sayHai">點選我</button>
</div>
<script src="../statics/vue.js"></script>
<script>
    let vm = new Vue({
        el: '#app',
        data: {
            message: '你好'
        },
        methods: {   //所有的方法都必須寫在 methods 裡面
            sayHai: function () {
                alert(this.message);
            }
        }
    });
</script>

4 雙向繫結

v-model 會忽略所有表單元素的 value、checked、selected 屬性,總是將 Vue 例項的資料作為資料來源

<!--model 和 view,兩者其一改變,另外一個也必定改變-->
<div id="app">
    輸入的文字:<input type="text" v-model="message"> 繫結的文字:{{message}}
</div>
<script src="../statics/vue.js"></script>
<script>
    let vm = new Vue({
        el: '#app',
        data: {
            message: ""
        }
    });
</script>
<div id="app">
    <select v-model="checked">
        <option disabled>--請選擇--</option>
        <option>A</option>
        <option>B</option>
        <option>C</option>
    </select>
    <span>選擇的是:{{checked}}</span>
</div>

<script src="../statics/vue.js"></script>
<script>
    let vm = new Vue({
        el: '#app',
        data: {
            checked: ''
        }
    });
</script>

5 元件基礎

  • 元件就是可以複用的 Vue 例項,本質就是一組可以重複使用的模板

  • Vue.component 註冊元件

<div id="app">
    <my-diy v-for="item in items" v-bind:info="item"></my-diy>
</div>

<script src="../statics/vue.js"></script>

<script>
    Vue.component("my-diy", {
        props: ['info'],
        template: '<li>{{info}}</li>'
    });

    let vm = new Vue({
        el: '#app',
        data: {
            items: ["Java", "Linux", "Python"]
        }
    });
</script>

6 Axios

  • Axios 是一個開源的可以用在瀏覽器和 Node.js 的非同步通訊框架,它的主要作用就是實現 Ajax 非同步通訊

偽造一個 json 資料,然後使用 axios 將其渲染到頁面

{
  "name": "荒天帝",
  "teacher": "柳神",
  "url": "https:www.xxxx.com",
  "address": {
    "street": "石村",
    "city": "荒域",
    "era": "亂古紀元末期"
  }
}
<!doctype html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
              content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Title</title>
        <!--解決網速慢時先顯示模板的問題-->
        <style>[v-clock]{ display: none;}</style>
    </head>
    
    <body>
        <div id="vue" v-clock>
            人物姓名:{{info.name}}<br>
            護道人: {{info.teacher}}<br>
            家庭住址: {{info.address.era}}-{{info.address.city}}-{{info.address.street}}<br>
            <a v-bind:href="info.url">連結</a>
        </div>

        <script src="../statics/vue.js"></script>
        <script src="../statics/axios.min.js"></script>
        <script>
            let vm = new Vue({
                el: '#vue',
                data(){ //這裡的 data() 是方法,不是原來的那個 data,那個是屬性
                    return { //這裡的返回值,必須是 json 格式,只需要指定格式不需要指定值
                        info: {
                            name: null,
                            teacher: null,
                            url: null,
                            address: {
                                street: null,
                                city: null,
                                era: null
                            }
                        }
                    }
                },
                mounted(){ //鉤子函式
                    axios.get("../statics/data.json")
                        .then(response=>(this.info=response.data));
                }
            });
        </script>
    </body>
</html>

7 計算屬性

計算屬性,它是一個屬性,但是計算又是一個函式,簡而言之,就是一個能夠將計算結果快取起來的屬性

<div id="app">
    <!--methods 裡的方法,呼叫需要使用括號,因為它是一個方法-->
    <p>Time01 : {{getTime01()}}</p>
    <!--computed 裡的方法,呼叫不需要使用括號,因為它是一個屬性-->
    <p>Time02 : {{getTime02}}</p>
</div>

<script src="../statics/vue.js"></script>

<script>
    let vm = new Vue({
        el: '#app',
        methods: {
            getTime01: function (ns) {
                return new Date();
            }
        },
        computed: { //計算屬性
            getTime02: function () {
                this.message;	//類似於 MyBatis 中的快取機制,只要發生重新整理(增刪改),快取立馬失效
                return new Date();
            }
        }
    });
</script>

8 插槽 slot

<div id="app">
    <todo>
        <todo-title slot="todo-title" v-bind:title="ti"></todo-title>
        <todo-items slot="todo-items" v-for="toIt in todoItems" v-bind:item="toIt"></todo-items>
    </todo>
</div>

<script src="../statics/vue.js"></script>

<script>
    Vue.component("todo", {
        template: '<div>\
                        <slot name="todo-title"></slot>\
                        <ul>\
                            <slot name="todo-items"></slot>\
                        </ul>\
                   </div>'
    });
    Vue.component("todo-title",{
        props: ['title'],
        template: '<div>{{title}}</div>'
    });
    Vue.component("todo-items",{
        props: ['item'],
        template: '<li>{{item}}</li>'
    });
    let vm = new Vue({
        el: '#app',
        data: {
            ti: '小說人物列表',
            todoItems: ['荒天帝','凌風','君莫邪']
        }
    });
</script>

9 自定義事件內容分發

Vue 的刪除操作要在元件中完成,那麼元件應該怎麼才能刪除 Vue 例項中的元素呢?這樣的功能就涉及到了引數傳遞和事件分發,可以使用 this.$emit('事件名', 引數) 來實現

仍然以上面的例子為例,要求點選刪除按鈕就刪除對應的條目

<div id="app">
    <todo>
        <todo-title slot="todo-title" v-bind:title="ti"></todo-title>
        <todo-items slot="todo-items" v-for="(toIt, index) in todoItems"
                    :item="toIt" :index="index" :key="index"
                    v-on:remove="removeItems(index)"></todo-items>
    </todo>
</div>
<script src="../statics/vue.js"></script>
<script>
    Vue.component("todo", {
        template: '<div>\
                        <slot name="todo-title"></slot>\
                        <ul>\
                            <slot name="todo-items"></slot>\
                        </ul>\
                   </div>'
    });
    Vue.component("todo-title",{
        props: ['title'],
        template: '<div>{{title}}</div>'
    });
    Vue.component("todo-items",{
        props: ['item', 'index'],
        template: '<li>{{item}} <button @click="remove">刪除</button></li>',
        methods: {
            remove: function (index) {
                //自定義事件分發
                this.$emit('remove', index);
            }
        }
    });
    let vm = new Vue({
        el: '#app',
        data: {
            ti: '小說人物列表',
            todoItems: ['荒天帝','凌風','君莫邪'],
            methods: {
                removeItems: function (index) { //刪除 todoItems 元素
                    this.todoItems.splice(index, 1);
                }
            }
        }
    });
</script>

10 Vue-cli

  • Vue-cli 是官方提供的一個腳手架,可以用來快速的生成 Vue 的模板專案

  • 它具有預先定義好的目錄結構以及基礎程式碼,較好比建立了一個骨架專案

  • 它主要具有:統一的目錄結構、本地除錯、熱部署、單元測試、整合打包上線的功能

  1. 安裝配置好 Node.js 之後,安裝兩個模組
npm install -g webpack vue-cli
  1. 然後隨便選擇一個資料夾建立我們的 myvue 專案,在當前目錄下,管理員身份執行終端,執行命令
vue init webpack myvue		//myvue 為專案名,不能出現大寫字母

出現如下報錯,大致意思就是網路的問題,無法從 github 上下載到 vuejs-templates/webpack,那我們就去離線安裝

先使用 git 將 webpack 克隆到本地

git clone [email protected]:vuejs-templates/webpack.git

然後在回到剛剛建立專案的目錄下,重新執行命令

//這裡的 E:\MyCode\test\webpack 是剛剛使用 git 克隆的專案路徑,myvue 仍然為專案名稱
vue init E:\MyCode\test\webpack myvue

為了瞭解 vue 專案,這裡全部選擇 No,後續手動安裝

執行成功後,可以發現專案已經成功建立

  1. 接下來是安裝該專案的所有依賴環境,首先終端進入該專案,然後執行 npm install
//進入專案根目錄
cd myvue
    
//安裝專案所需的依賴
npm install
  1. 安裝完所有依賴之後,使用 npm run dev 啟動專案,然後訪問 https://localhost:8080 埠,就可以訪問初始的 vue 專案了

11 路由

  • 由於 vue 只針對於檢視層,所以如法控制檢視跳轉,此時就需要使用 vue-router 外掛來實現

  • 若要進行類比,他就類似於 Java 的 Servlet,控制檢視的跳轉

  1. 首先使用 npm 安裝該外掛
npm install vue-router --save-dev
  1. 安裝好之後,為了測試,我們在 compentents 元件目錄下,新建兩個元件
  • 關於我元件
<template>
    <h2>歡迎來到關於我頁面</h2>
</template>

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

<style scoped></style>
  • 後臺頁面元件
<template>
    <h2>歡迎來到後臺頁面</h2>
</template>

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

<style scoped></style>
  1. 然後去 router 路徑下新建一個 index.js,去配置路由
import Vue from 'vue'
import Router from 'vue-router'
import InfoPage from "../components/InfoPage";
import MainPage from "../components/MainPage";

Vue.use(Router)

export default new Router({
  routes: [
    {
      name: 'MainPage',		//路由的名稱
      path: '/main',		//路由進行跳轉的路徑,對應 <router-link> 中的 to 所指的屬性,及要跳轉的連結地址
      component: MainPage	//進行路由註冊的元件名稱
    },
    {
      name: 'InfoPage',
      path: '/info',
      component: InfoPage
    }
  ]
})
  1. 使用 App.vue 來模仿網站主頁,將測試的兩個元件使用 router-link 連結進來
<template>
  <div id="app">
    <h2>網站首頁</h2>
    <router-link to="/info">關於我</router-link>
    <router-link to="/main">後臺主頁</router-link>
    <!-- router-view 標籤必須要有,否則路由跳轉成功後,雖然地址已經改變,但是不顯示頁面-->
    <router-view></router-view>		
  </div>
</template>

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

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
  1. 然後去主配置 main.js 中將配置的路由 ./components/index.js 匯入
import Vue from 'vue'
import App from './App'
import router from './router/index'

Vue.config.productionTip = false

new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})
  1. 在終端使用命令 npm run dev 啟動專案,訪問 8080 埠,網站主頁面顯示成功
  1. 分別點選下面的兩個元件,可以看到會成功跳轉到相應的頁面,測試成功

12 路由巢狀

在實際的業務開發中,經常會遇到以下需求,當用戶登入之後(假設路由的路徑為 /user),接下來使用者所有的操作都會在該路由路徑下進行二次巢狀,比如使用者個人資訊頁面(/user/info)、使用者列表頁面(/user/list)等等,諸如此類,就需要進行路由巢狀

  • 路由配置
import Vue from 'vue'
import Router from 'vue-router'

import User from '../user'
import UserInfo from '../views/user/Info'
import UserList from '../views/user/List'

Vue.use(Router);

export default new Router({
    routes: [
        {
            path: '/user',
            component: User,
            children: [
                {
                    path: '/user/info',
                    component: UserInfo
                },
                {
                    path: '/user/list',
                    component: UserList
                }
            ]
        }
    ]
});
  • vue 樣式配置
<templates>
    <router-link to='/user'>使用者首頁</router-link>
    <router-link to='/user/info'>使用者資訊頁面</router-link>
    <router-link to='/user/list'>使用者列表頁面</router-link>
    <router-view></router-view>
</templates>

13 引數傳遞和重定向

13.1 引數傳遞

還是以使用者資訊為例,要根據不同使用者來展示不同的資訊,就需要進行引數傳遞

  • 路由配置
import Vue from "vue"
import VueRouter from "vue-router";

import User from "../views/User"
import UserInfo from "../views/user/Info"

Vue.use(VueRouter);

export default new VueRouter({
  routes: [
    {
      path: '/user',
      name: 'User',
      component: User,
      children: [
        {
          path: '/user/info/:username',
          name: 'UserInfo',
          component: UserInfo,
          props: true
        }
      ]
    }
  ]
});
  • vue 樣式配置
<template>
  <div id="app">
    <router-link v-bind:to="{name: 'UserInfo', params: {username: 'Jack'}}">使用者資訊頁面</router-link>
    <router-view></router-view>
  </div>
</template>
  • 使用者資訊頁面取值
<template>
  <div>
    使用者名稱為:{{username}}
  </div>
</template>

<script>
  export default {
    props: ['username'],
    name: "Info",
  }
</script>

<style scoped></style>
13.2 重定向
  • 路由配置
import Vue from "vue"
import VueRouter from "vue-router";

import User from "../views/User"
import GoHome from "../views/user/GoHome"

Vue.use(VueRouter);

export default new VueRouter({
  routes: [
    {
      path: '/user',
      name: 'User',
      component: User,
      children: [
        {
          path: '/goHome',
          component: GoHome,
          redirect: '/main'
        }
      ]
    }
  ]
});
  • vue 配置
<template>
  <div id="app">
    <router-link to="/user/goHome">回到首頁</router-link>
    <router-view></router-view>
  </div>
</template>

14 404 與路由鉤子

路由預設有兩種模式:history 與 hash 模式

若要修改模式,只需要設定 mode 即可

export default new Router({
    mode: 'history',
    routes: []
});
14.1 404

除過業務規定的請求之外,其他的請求都應該走 404 頁面

import Vue from "vue"
import VueRouter from "vue-router";

import NotFound from "../views/NotFound"

Vue.use(VueRouter);

export default new VueRouter({
    routes: [
        //其他路由配置資訊.....
        {
            path: "*",
            component: NotFound
        }
    ]
});
14.2 路由鉤子
<script>
    export default {
      //其他配置...

      beforeRouteEnter: ((to, from, next) => {
        console.log("進入路由之前");
        next();
      }),
      beforeRouteLeave: ((to, from, next) => {
        console.log("進入路由之後");
        next();
      })
    }
</script>