前端筆記之Vue(二)組件&案例&props&計算屬性

来源:https://www.cnblogs.com/rope/archive/2019/04/29/10736326.html
-Advertisement-
Play Games

一、Vue組件(.vue文件) 組件 (Component) 是 Vue.js 最強大的功能之一。組件可以擴展 HTML 元素,封裝可重用的代碼。在較高層面上,組件是自定義元素,Vue.js 的編譯器為它添加特殊功能。在有些情況下,組件也可以表現為用 is 特性進行了擴展的原生 HTML 元素。 所 ...


一、Vue組件(.vue文件)

組件 (Component) Vue.js 最強大的功能之一。組件可以擴展 HTML 元素,封裝可重用的代碼。在較高層面上,組件是自定義元素,Vue.js 的編譯器為它添加特殊功能。在有些情況下,組件也可以表現為用 is 特性進行了擴展的原生 HTML 元素。

所有的 Vue 組件同時也都是 Vue 的實例,所以可接受相同的選項對象 (除了一些根級特有的選項) 並提供相同的生命周期鉤子。

說白了,就是HTMLCSSJS行為的一個封裝。

 

Vue中組件的實例化是對程式員不透明的,組件必須在components中進行“註冊”才能使用。

Vue中用K:V對的形式定義類,讓你自由的註冊名字,Vue官方推薦使用含有短橫的名字來表示自定義組件。

 

翻譯.vue文件需要安裝vue-loader依賴:

https://vue-loader.vuejs.org/zh-cn/

https://vue-loader-v14.vuejs.org/zh-cn/configurations/pre-processors.html

 

安裝其他4個開發依賴:

npm install --save-dev css-loader
npm install --save-dev vue-loader
npm install --save-dev vue-style-loader
npm install --save-dev vue-template-compiler

 

修改webpack的配置(關於vue-loader的配置)官網找:

https://vue-loader-v14.vuejs.org/zh-cn/configurations/pre-processors.html


1.1組件的寫法1

.vue文件的結構:

<template></template>     html結構
<script></script>            js程式
<style></style>            樣式表

 App.vue父組件:

<template>
    <h1>我是App父組件{{a}}</h1>
</template>
<script>
    export default {
        data(){
            return {
                a:100
            }
        }
    }
</script>
<style></style>
示例代碼

 

有了App.vue組件就可以在main.js中通過import引入,並註冊:

import Vue from 'vue';
import App from './App.vue';

new Vue({
    el : "#app",
    data : {

    },
    components : {
        App
    }
})

 

index.html頁面中使用即可:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <title>Document</title>
</head>
<body>
    <div id="app">
        <App></App>
    </div>
</body>
<script type="text/javascript" src="dist/all.js"></script>
</html>

此時看見App父組件的內容了


1.2組件的寫法2

使用vue2新增的render()函數

index.html頁面中就不用放在<App></App>自定義標簽了,也不需要註冊了。

main.js

import Vue from 'vue';
import App from './App.vue';

new Vue({
    el : "#app",
    render : (h)=> h(App)
})

 

Vue中不允許出現片段標簽,必須用一個標簽包裹所有

<template>
    <div>
        <h1>我是app組件{{a}}</h1>
        <h1>我是app組件{{a}}</h1>
    </div>
</template>
錯誤寫法:
<template>
    <h1>我是app組件{{a}}</h1>
    <h1>我是app組件{{a}}</h1>
</template>

 

如果有兩個組件就需要有一個components的文件夾 裡面可以放.vue組件

mian.vue

<style>
</style>
<template>
    <div>
        <h1>我是mian組件{{a}}</h1>
    </div>
</template>
<script>
    export default{
        data(){
            return{
                a : 100
            }
        }
    }
</script>

 

組件在App.vue裡面使用

<style>
</style>
<template>
    <div>
        <vue-main></vue-main>
        <VueMain></VueMain>
    </div>
</template>
<script>
import VueMain from "./components/main.vue"
export default {
    data(){
        return {
            a: 100
        }
    },
    components:{
        VueMain
    }
}
</script>

 

使用的時候以下兩種方法:

<VueMain></VueMain> 

等價於:

<vue-main></vue-main>

1.3關於data

在前面看到,在new Vue()的時候,創建或註冊模板時,傳入一個data屬性作為用來綁定的數據。是可以給data直接賦值為一個對象的。但是在組件中,data必須是一個函數,而不能直接把一個對象賦值給它。

 

1種,在main.js主入口中的寫法:

new Vue({
    el:'#app',
    data:{
            
    }
})

 

2種,在組件中data選項必須是一個函數:

new Vue({
    el:'#app',
    data(){
        return { //返回一個唯一的對象,不要和其他組件共用一個對象進行返回
                
        }
    }
})

 

【區別】:

1)在簡單的Vue實例中,沒什麼區別,因為你new出的對象不會被覆用。

new Vue({...})

2)但在組件中,因為可能在多處調用同一組件,所以為了不讓多處的組件共用同一data對象,只能返回函數。


 

二、案例

2.1調色板

<template>
    <div>
        <div class="box" :style="{background:`rgb(${r},${g},${b})`}"></div>
        <p>
            <input type="range" min="0" max="255" v-model="r">
            <input type="number" min="0" max="255" v-model="r">
        </p>
        <p>
            <input type="range" min="0" max="255" v-model="g">
            <input type="number" min="0" max="255" v-model="g">
        </p>
        <p>
            <input type="range" min="0" max="255" v-model="b">
            <input type="number" min="0" max="255" v-model="b">
        </p>
    </div>
    
</template>
<script>
    export default {
        data(){
            return {
                r : 100,
                g : 100,
                b : 100
            }
        }
    }
</script>
<style>
    .box{
        width: 200px;
        height: 200px;
    }
</style>
示例代碼

2.2購物車

<template>
    <div>
        <table>
            <tr>
                <th>號碼</th>
                <th>東西</th>
                <th>價格</th>
                <th>數量</th>
                <th>小計</th>
            </tr>
            <tr v-for="item in carts">
                <td>{{item.id}}</td>
                <td>{{item.title}}</td>
                <td>{{item.price}}</td>
                <td>
                    <button @click="minus(item.id)">-</button>
                    <input  type="number" min="0" v-model="item.number">
                    <button @click="add(item.id)">+</button>
                </td>
                <td>{{item.number * item.price}}</td>
            </tr>
        </table>
        <h1>總價格:{{this.carts.reduce((a,b)=>a + b.price * b.number , 0)}}</h1>
    </div>
</template>
<script>
    export default {
        data(){
            return {
                carts : [
                    {"id" : 1 , "title" : "空調" , "price" : 5000, "number" : 1},
                    {"id" : 2 , "title" : "手機" , "price" : 3000, "number" : 1},
                    {"id" : 3 , "title" : "滑鼠" , "price" : 200 , "number" : 1}
                ]
            }
        },
        methods : {
            add(id){
                //this.carts.filter(item=>item.id == id)[0].number++
                //vue不能識別數組某個項單獨修改!!要改必須直接改變數組!!
                this.carts = this.carts.map(item=>item.id == id ? {...item , "number" : item.number +}: item);
            },
            minus(id){
                //this.carts.filter(item=>item.id == id)[0].number--
                this.carts = this.carts.map(item=>item.id == id ? {...item , "number" : item.number -}: item);
            }
        }
    }
</script>
<style>
     table,tr,td,th{border:1px solid red;}
     td{width:200px;height:60px;}
</style>
示例代碼

2.3選項卡

<style>
.box {
    width: 600px;height: 400px;
    margin: 10px auto;
    border: 1px solid #333;
        header {
        ul {
            overflow: hidden;
            li {
                float: left;
                width: 33.333%;
                height: 40px;
                line-height: 40px;
                text-align: center;
            }
            li.cur {
                background: red; color: #fff;
            }
        }
    }
}
</style>
<template>
    <div class="box">
        <header>
            <ul>
                <li v-for="(item,index) in tabNav" :class="{cur:item.click}" @click="changeTab(dex)">{{item.title}}</li>
            </ul>
        </header>
        <div class="content">
            <div v-show="tabIndex == 0">
                新聞新聞新聞新聞新聞
            </div>
            <div v-show="tabIndex == 1">
                軍事軍事軍事軍事軍事
            </div>
            <div v-show="tabIndex == 2">
                圖片圖片圖片圖片圖片
            </div>
        </div>
    </div>
</template>
<script>
export default {
    data() {
        return {
            tabNav: [
                {title: "新聞", click: true},
                {title: "軍事", click: false},
                {title: "圖片", click: false}
            ],
            tabIndex: 0
        }
    },
    methods:{
      changeTab(index){
          // 遍歷tabNav數組 進行迴圈 去掉所有類
          this.tabNav.forEach(function(item){
              item.click = false
          });
          // 點擊的那個tab 加類
          this.tabNav[index].click = true
          // 改變索引
          this.tabIndex = index
      }
    }
}
</script>
示例代碼

2.4三級聯動

<template>
    <div>
        <select v-model="sheng">
            <option v-for="item in info" :value="item.name">
                {{item.name}}
            </option>
        </select>

        <select v-model="shi">
            <option 
                v-for="item in info.filter(i=>i.name == sheng)[0].city" 
                :value="item.name"
            >
                {{item.name}}
            </option>
        </select>

         <select v-model="xian">
            <option 
v-for="item in info.filter(i=>i.name==sheng)[0].city.filter(i=>i.name==shi)[0].area" 
                :value="item"
            >
                {{item}}
            </option>
        </select>
        <h1>你的地址{{sheng}}{{shi}}{{xian}}</h1>
    </div>
</template>
<script>
    import info from "./info.js"; //引入全國省市數據
    export default {
        data(){
            return {
                info ,
                sheng:"廣東省",
                shi : "廣州市",
                xian: "花都區"
            }
        },
        watch : {
            sheng(){
                //當data中的sheng變化的時候,觸發
              this.shi = info.filter(i=>i.name == this.sheng)[0].city[0].name;
              this.xian=info.filter(i=>i.name==this.sheng)[0].city.filter(i=>i.name==this.shi)[0].area[0]
            }
        }
    }
</script>
示例代碼

簡化:

<template>
    <div>
         <!-- <select v-model="sheng" @change="changeSheng($event)"> -->
         <select v-model="sheng">
             <option v-for="item in info" :value="item.name">
                 {{item.name}}
             </option>
         </select>

         <select v-model="shi">
             <option v-for="item in allShi()" :value="item.name">
                 {{item.name}}
             </option>
         </select>

         <select v-model="xian">
             <option v-for="item in allXian()" :value="item">
                 {{item}}
             </option>
         </select>
    </div>
</template>
<script>
    import info from "../lib/info.js";
    export default {
        data(){
            return {
                info,
                sheng:"廣東省",
                shi:"廣州市",
                xian:"天河區"
            }
        },
        methods:{
            // changeSheng(e){
            //     this.shi = info.filter(i=>i.name == this.sheng)[0].city[0].name;
            //     this.xian = info.filter(i=>i.name == this.sheng)[0].city.filter(i=>i.name == this.shi)[0].area[0];
            // }
            allShi(){
                return info.filter(i=>i.name == this.sheng)[0].city;
            },
            allXian(){
                return info.filter(i=>i.name == this.sheng)[0].city.filter(i=>i.name == this.shi)[0].area
            }
        },
        watch:{
            //當data中的sheng變化的時候,觸發這個函數
            sheng(){
                this.shi = info.filter(i=>i.name == this.sheng)[0].city[0].name;
                this.xian = info.filter(i=>i.name == this.sheng)[0].city.filter(i=>i.name == this.shi)[0].area[0];
            }
        }
    }
</script>
示例代碼

三、props(★)

使用 Prop 傳遞數據

組件實例的作用域是孤立的。這意味著不能 (也不應該) 在子組件的模板內直接引用父組件的數據。父組件的數據需要通過 prop 才能下發到子組件中。

動態 Prop

與綁定到任何普通的 HTML屬性相類似,可以用v-bind來動態地將 prop 綁定到父組件的數據。每當父組件的數據變化時,該變化也會傳導給子組件

 

1) 組件的使用:子組件不能直接改變父組件傳入的值,必須調用父組件的函數來改變(引用類型值能直接改)

2) 組件的思維:所有子組件不需要對其它兄弟組件負責,只對父組件負責即可。


 

3.1傳基本類型值

如果想讓父組件data中的數據傳遞給子組件,需要使用標簽屬性傳遞(如果是動態值用v-bind

子組件需要使用props接收父組件的值,如果父組件中修改a值,同時會影響子組件。

 

App.vue父組件

<template>
    <div>
        <Haha a="8"></Haha>
        <Haha :b="a"></Haha>
    </div>
</template>
<script>
    import Haha from "./components/Haha.vue";
    export default {
        data(){
            return {
                a : 100
            }
        },
        components : {
            Haha
        }
    }
</script>

 

Haha.vue子組件

<template>
    <div>
        <h1>我是子組件{{a}} {{b}}</h1>
    </div>
</template>
<script>
    export default {
        props : ["a","b"],  //接收父組件傳過來的屬性的值
        data(){
            return {
           a : 100   //從父組件接收有a,這裡就不能有同名的a了
            }
        }
    }
</script>

3.2子組件要改props必須調用父親傳的函數

子組件不能直接改變父組件傳入的值,必須調用父組件的函數來改變

傳值就要傳它的改變函數給子組件,本質上還是調用父親的函數去改變。

 

App.vue父組件傳值:

<template>
    <div>
        <h1>父組件{{a}}</h1>
        <button @click="add">父組件按鈕+</button>
        <button @click="minus">父組件按鈕-</button>

        <Haha :a="a" :add="add" :minus="minus"></Haha>
    </div>
</template>
<script>
    import Haha from "./components/Haha.vue";
    export default {
        data(){
            return {
                a : 100
            }
        },
        components : {
            Haha
        },
        methods : {
            add(){
                this.a++;
            },
            minus(){
                this.a--;
            }
        }
    }
</script>

 

Haha.vue子組件接收

<template>
    <div>
        <h1>我是子組件{{a}}</h1>
        <button @click="add">子組件按鈕+</button>
        <button @click="minus">子組件按鈕-</button>
    </div>
</template>
<script>
    export default {
        //子組件不能直接改父組件的數據,要改就必須傳父組件的函數來改變
        props : ["a","add","minus"],  //接收父組件傳過來的屬性的值
        data(){
            return {

            }
        }
    }
</script>


3.3傳引用類型值可以直接改

如果傳入引用類型值,子組件是可以直接改父組件的值,而不報錯的。

 

App.vue父組件

<template>
    <div>
        <h1>父組件{{obj.a}}</h1>
        <Haha :obj="obj"></Haha>
        <button @click="add">父組件按鈕+</button>
    </div>
</template>
<script>
    import Haha from "./components/Haha.vue";
    export default {
        data(){
            return {
                obj : {
                    a : 100
                }
            }
        },
        components : {
            Haha
        },
        methods : {
            add(){
                this.obj.a++;
            }
        }
    }
</script>

 

Haha.vue子組件

<template>
    <div>
        <h1>我是子組件{{obj.a}}</h1>
        <button @click="add">子組件按鈕+</button>
    </div>
</template>
<script>
    export default {
        // 子組件不能直接改父組件的數據,要改就必須傳父組件的函數來改變
        props : ["obj"],  //接收父組件傳過來的屬性的值
        methods:{
            add(){
                this.obj.a++
            }
        }
    }
</script>

l 單向數據流

Prop 是單向綁定的:當父組件的屬性變化時,將傳導給子組件,但是反過來不會。這是為了防止子組件無意間修改了父組件的狀態,來避免應用的數據流變得難以理解。

另外,每次父組件更新時,子組件的所有 prop 都會更新為最新值。這意味著你不應該在子組件內部改變 prop。如果你這麼做了,Vue 會在控制台給出警告。

 


3.4字面量語法 vs 動態語法

使用v-bind是動態語法,不使用就是字元串

app.vue父組件:

<div>
    <Haha a="a"></Haha>
</div>
<script>
import Haha from "./components/Haha.vue"
export default {
    data() {
        return {
            a: 100
        }
    }
    components:{
        Haha
    }
}
</script>

 

Haha.vue子組件:

<template>
    <div> 
        <h1>{{typeof a}}</h1> 
    </div>
</template>
<script>
    export default{
        props:["a"]
    }
</script>

這樣傳遞得到的是字元串的 "a"

 

初學者常犯的一個錯誤是使用字面量語法傳遞數值:

因為它是一個字面量 prop,它的值是字元串 "a" 而不是一個數值。如果想

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Vue.js是一款流行的開源JavaScript前端框架,旨在更好地組織與簡化Web開發。Vue所關註的核心是MVC模式中的視圖層,同時,它也能方便地獲取數據更新,並通過組件內部特定的方法實現視圖與模型的交互。由尤雨溪在2014年2月發佈的。 一 基本語法 1. vue的使用要從創建Vue對象開始 ...
  • 1. find()與findIndex()    find()方法,用於找出第一個符合條件的數組成員。它的參數是一個回調函數,所有數組成員依次執行該回調函數,直到找出第一個返回值為true的成員,然後返回該成員。如果沒有符合條件的成員,則返回undefined。 [1, 2, 5 ...
  • js動態數字時鐘 主要用到知識點: 主要是通過數組的一些方法,如:Array.from() Array.reduce() Array.find() 時間的處理和渲染 js用到面向對象的寫法 實現的功能 炫酷的數字時間效果 直接看效果 html: css: js: 參考自:騰訊課堂渡一教育 ...
  • 在項目中有些邏輯或者請求依賴另一個非同步請求,大家常用的方法是回調函數。現在有個高大上的解決方案:await async 。 async 是“非同步”的簡寫,而 await 可以認為是 async wait 的簡寫。所以應該很好理解 async 用於申明一個 function 是非同步的,而 await ...
  • $root vue狀態管理使用vuex,如果項目不大,邏輯不多,name我們沒必要用vuex給項目增加難度,只需要用$root設置vue實例的data就行了,如下 main.js a.vue b.vue $parent parent能夠訪問父組件的屬性和方法 parent.vue child.vue ...
  • 這次我們主要來分享11個在日常教程中不常被提及的JavaScript小技巧,他們往往在我們的日常工作中經常出現,但是我們又很容易忽略。 1、過濾唯一值 Set類型是在 ES6中新增的,它類似於數組,但是成員的值都是唯一的,沒有重覆的值。結合擴展運算符(...)我們可以創建一個新的數組,達到過濾原數組 ...
  • 最近我們的表格中,需要更改數據的顯示方式,就是jqgrid中以樹形的方式顯示。請先看圖: 就是簡單的這種從屬方式。但是因為這個沒有找到官方的文檔(後來找到了,但是發現是翻譯過來的,也不是很清楚),所以做出來稍微的有點困難,好在方法總比困難多。這個問題還是解決了,在這裡我記錄一下。方便以後的小伙伴們運 ...
  • 在<script>中: $(function(){ var num=$(".price").length;/*獲取應用了class="price"的標簽數量*/ for(var i=0;i<num;i++){ if($(".price")[i].innerText!="") $(".price")[ ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...