­

Vue 組件實戰

Vue 組件

Vue 生命周期鉤子

axios實現數據請求

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./js/vue.js"></script>
    <script src="//unpkg.com/axios/dist/axios.min.js"></script>

</head>
<body>
<div id="app">
    <ul>
        <li v-for="film in films_list">
            <p>電影名字是:{{film.name}}</p>
            <img :src="film.poster" alt="" width="100px" height="150px">
            <p>電影介紹:{{film.synopsis}}</p>
        </li>
    </ul>

</div>

</body>
<script>

    var vm = new Vue({
        el: '#app',
        data: {
            films_list:[]
        },
        created() {
            axios.get('//127.0.0.1:5000/films').then(res => {
                console.log(res.data)
                this.films_list=res.data.data.films
            })

        }
    })
</script>
</html>
from flask import Flask,make_response,jsonify

app=Flask(__name__)
@app.route('/films')
def films():
    import json
    with open('./movie.json','r',encoding='utf-8') as f:
        res=json.load(f)
    obj = make_response(jsonify(res))
    obj.headers['Access-Control-Allow-Origin']='*'
    return obj

if __name__ == '__main__':
    app.run()

image


計算屬性

我們可以通過計算屬性computed來緩存計算,什麼意思呢?

在Vue中我們可以使用插值來展示數據,插值的普通函數,只要頁面一刷新,函數就會重新運算,不管和函數有關沒關的值都會變,函數也會重新計算,導致運行效率降低;

那麼我們可以將自定義函數寫在computed中來控制,把函數當成屬性來用,調用不需要加括號,只有這個函數使用的屬性(變量)發生變化,函數才重新運算,這樣做可以減輕壓力,減少資源浪費

案例一:首字母大寫

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>計算屬性</title>
    <script src="//cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <link href="//cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="//cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
    <script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
    <div style="font-size: 20px">
        輸入內容:<input type="text" v-model="mytext"> ----》 {{mytext.substring(0,1).toUpperCase()+mytext.substring(1)}}
        <br><br>
        <p>函數綁定(會刷新頁面,也不推薦):<input type="text" :value="getName()"></p>
        <p>計算屬性(推薦):<input type="text" :value="getName1"></p>
    </div>

    <hr>
    <div style="font-size: 20px">
         <p>輸入內容:<input type="text" v-model="mytext1"> -----》{{mytext1}}</p>
    </div>
</div>
</body>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            mytext: '',
            mytext1:''
        },
        methods:{
            getName(){
                console.log('函數方式,我執行了')
                return this.mytext.substring(0,1).toUpperCase()+this.mytext.substring(1)
            }
        },
        //計算屬性
        computed:{
            getName1(){
                console.log('計算屬性,我執行了')
                return this.mytext.substring(0,1).toUpperCase()+this.mytext.substring(1)
            }

        }
    })
</script>
</html>

計算屬性

我們可以發現只有和屬性相關的才會打印,如果下面輸入內容只是打印了普通函數,就算函數內和mytext1不相關

案例二:過濾案例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>過濾案例</title>
    <script src="//cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box">
    <p><input type="text" v-model="myText"  placeholder="請輸入要篩選的內容:"></p>
    <ul>
        <li v-for="data in newList">{{data}}</li>
    </ul>
</div>
</body>
<script>
    var vm = new Vue({
        el: '#box',
        data: {
            myText: '',
            dataList: ['a', 'at', 'atom', 'be', 'beyond', 'cs', 'csrf'],
        },

        computed:{

            newList(){
                var _this = this
                console.log('執行了',_this)
                 var datalist2 = _this.dataList.filter(function(item){
                    console.log(_this)
                     return item.indexOf(_this.myText) > -1

                })
                return datalist2

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

計算屬性2


監聽屬性

watch來設置監聽屬性,當mytext發生變化,就會執行和mytext綁定的函數方法

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./js/vue.js"></script>
</head>
<body>
<div id="app">

    <input type="text" v-model="mytext">--->{{mytext}}


</div>

</body>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            mytext: '',
        },
        watch: {
            // 只要mytext發生變化,就會執行該函數
            mytext: function () {
                console.log('我變化了,執行')

            }
        }


    })
</script>
</html>

監聽屬性


局部組件

寫在components里的是局部組件,位置被限制,只能再局部使用

比如如下例子中,Top組件只能在只能再id為app的標籤(div)內使用, Top組件內如果想再定義子組件,只能在該組件內的template中的div內使用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
    <Top></Top>
    <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
    <Bottom></Bottom>
</div>

</body>
<script>
    var vm = new Vue({
        el: '#app',
        data: {},
        // 定義再這裏面的叫局部組件,只能再局部使用,只能再id為app的標籤內使用
        components: {
            'Top': {
                //寫在一個div里
                template: `
                    <div>
                        <h1 style="background: pink;font-size: 60px;text-align: center">{{name}}</h1>
                        <hr>
                        <button @click="handleC">點我看美女</button>
                    </div>
                `,
                //data是函數,可以設置返回值
                data() {
                    return {
                        name: "我是頭部"
                    }
                },
                methods: {
                    handleC() {
                        alert('美女')
                    }
                },
            },
            'Bottom': {
                template: `
                    <div>
                        <hr>
                        <h1 style="background: green;font-size: 60px;text-align: center">{{name}}</h1>

                    </div>
                `,
                data() {
                    return {
                        name: "我是尾部"
                    }
                },

            },

        },


    })
</script>
</html>

局部組件


全局組件

任意位置都可以使用但是也得是在vue實例託管的div範圍內

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
    <top></top>


</div>

</body>
<script>
    // 定義全局組件,任意位置都可以用,局部內也可以使用
    Vue.component('top', {
            template: `
                <div>
                    <h1 style="background: pink;font-size: 60px;text-align: center">{{name}}</h1>
                    <hr>
                    <button @click="handleC">點我看美女</button>
                </div>
            `,
            data() {
                return {
                    name: "我是頭部"
                }
            },
            methods: {
                handleC() {
                    alert('美女')
                }
            },

        },)

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

全局組件


組件通信之父傳子

組件間data數據不同享,數據傳遞,如果我們想從父組件傳遞到子組件數據通過props自定義屬性來實現,比如如下例子:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="//cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <link href="//cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="//cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
    <script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
    子組件顯示:<top :value="handleName"></top>
    <hr>
    父組件輸入內容:<input type="text" v-model="handleName">

</div>

</body>
<script>

    Vue.component('top', {
        template: ` <div>
                    <h1 style="background: tomato;font-size: 30px;text-align: center">{{value}}</h1>
                    </div>             `,
        // 必須叫props,數組內放自定義屬性的名字
        props:{
            value: String,  // key是自定義屬性名,value是類型名,如果是別的類型就報錯
        },
        //props也可以寫成數組的形式,不帶驗證功能
        // props:['value',]
    })
    var vm = new Vue({
        el: '#app',
        data: {
            handleName: ''
        }
    })
</script>
</html>

父傳子


組件通信之子傳父

ps:Vue內置的對象都以$xx出現

我們可以通過自定義事件來實現子組件向父組件傳遞數據,在子組件中使用$emit('自定義事件',參數)來實現

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="//cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <link href="//cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="//cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
    <script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
<top @myevent="handleRecv"></top>
    <hr>
  <h1 style="background: green;font-size: 60px;text-align: center">父組件</h1>
 <p>接收子組件發送的數據:{{childText}}</p>
</div>

</body>
<script>

    Vue.component('top', {
        template: ` <div>
                        <h1 style="background: tomato;font-size: 60px;text-align: center">{{myheader}}</h1>
                        <p>子組件輸入內容:<input type="text" v-model="text"></p>
                        <p><button class="btn-success"  @click="handleSend">向父組件發送數據</button></p>
                    </div>             `,
        data(){
            return {
                myheader:'子組件',
                text:''
            }
        },
        methods:{
            handleSend(){
                //myevent是自定義事件,代表將子組件的text交給myevent事件處理
                this.$emit('myevent',this.text)
            }
        }

    })
    var vm = new Vue({
        el: '#app',
        data: {
            //接收子組件的數據
            childText:''
        },
        methods: {
            handleRecv(data){
                // 接收參數,賦值給父組件的childText
                this.childText=data
            }
        }
    })
</script>
</html>

子傳父


ref屬性(組件間通信)

普通標籤使用

普通標籤使用ref屬性,通過$refs獲取到的就是ref屬性所在的標籤,獲取到的是一個對象,如果多個標籤寫了ref屬性,那麼就將所有帶ref屬性的標籤弄到一個對象中,可以對html進行操作設置等,如下示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="//cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <link href="//cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="//cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
    <script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
    <h1 style="align-content: center">普通標籤使用ref</h1>
    <p><input type="text" ref="myinput"></p>
    <p><img src="" height="100px" width="100px" ref="myimg"></p>
    <p><button @click="handleC">點我</button>
</p>
</div>
</body>
<script>

    let vm = new Vue({
        el: '#app',
        data: {
             text:''
        },
        methods: {
            handleC(){
                console.log('我被點了')
                console.log(this.$refs)  // 是所有標籤寫了ref屬性的對象{myinput:真正的標籤,myimg:真正的標籤}
                console.log(this.$refs.myinput.value)
                //設置值
                this.$refs.myinput.value='HammerZe'
                //設置src屬性,顯示圖片
                this.$refs.myimg.src='//img0.baidu.com/it/u=3608430476,1945954109&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=494'
            }
        }
    })
</script>
</html>

ref屬性1

組件使用ref屬性

ref屬性,如果放在組件上,就是當前組件對象

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="//cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <link href="//cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="//cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
    <script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 組件使用ref屬性   -->
<top ref="top"></top>
<p>通信:<input type="text" v-model="text"></p>
<p>父組件按鈕:<button @click="handleC">點我</button></p>
</p>
</div>
</body>
<script>
   Vue.component('top', {
        template: `
            <div>
                <h1>{{myheader}}</h1>
                <p>子組件按鈕:<button @click="handleC">點我看美女</button></p>
                <hr>
            </div>
        `,
        data() {
            return {
                myheader: "頭部",
            }
        },
        methods:{
            handleC(){
                alert("美女")
            }
        }



    },)
    let vm = new Vue({
        el: '#app',
        data: {
             text:''
        },
        methods: {
        //放在組件上
        handleC() {
             console.log(this.$refs.top) //VueComponent {_uid: 1, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …}
            /*子傳父*/
            // 父組件拿子組件的值
            console.log(this.$refs.top.myheader)
            // this.text=this.$refs.top.myheader
            // 父組件調用子組件的方法
            this.$refs.top.handleC()

            /*父傳子*/
            this.$refs.top.myheader=this.text
        }
        }
    })
</script>
</html>

ref屬性2

事件總線(不常用)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="js/vue.js"></script>
</head>
<body>
<div id="box">
    <child1></child1>
    <child2></child2>
</div>
</body>
<script>
    var bus=new Vue() //new一個vue的實例,就是中央事件總線
    Vue.component('child1', {
        template: `<div>
            <input type="text" ref="mytext">
            <button @click="handleClick">點我</button>
        </div>`,
        methods:{
            handleClick(){
                bus.$emit('suibian',this.$refs.mytext.value) //發佈消息,名字跟訂閱消息名一致
            }
        }
    })
    Vue.component('child2', {
        template: `<div>
                    <div>收到的消息 {{msg}}</div>
                    </div>`,
        data(){
            return {msg:''}
        },
        mounted(){
            //生命周期,當前組件dom創建完後悔執行
            console.log('當前組件dom創建完後悔執行')
            //訂閱消息
            bus.$on('suibian',(item)=>{
                console.log('收到了',item)
                this.msg=item
            })
        }
    })
    var vm = new Vue({
        el: '#box',
        data: {},
        methods: {
            handleClick() {
                console.log(this)
                //this.$refs.mytext 獲取到input控件,取出value值
                console.log(this.$refs.mytext.value)
                console.log(this.$refs.mychild.text)
                // this.$refs.mychild.add()
                this.$refs.mychild.add('傳遞參數')

            }
        }

    })
</script>
</html>

動態組件和keep-alive

動態組件:實現點擊不同的連接顯示不同的頁面,實現跳轉,使用component標籤,用is屬性綁定,指定哪個顯示哪個

keep-alive:通過keep-alive標籤實現組件不銷毀,保留原來輸入的內容

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./js/vue.js"></script>
</head>
<style>
    #menu {
        font-size: 18px;
        font-weight: bold;
    }

    #menu li {
        text-decoration: none; /*去掉前面的圓點*/
        list-style: none;
        float: left;
        margin-right: 20px;

    }

</style>
<body>
<div id="app">
    <ul id="menu">
        <li @click="changeC('index')">首頁</li> &nbsp;
        <li @click="changeC('order')" >訂單</li>
        <li @click="changeC('good')">商品</li>
    </ul>


    <keep-alive>
        <component :is='who'></component>
    </keep-alive>


</div>

</body>
<script>
    //三個組件
    Vue.component('index', {
        template: `
            <div style="overflow:hidden;">
                <h1>首頁內容</h1>
            </div>
        `,
    },)
    //保留輸入的訂單信息
    Vue.component('order', {
        template: `
            <div>
                <h1>訂單內容</h1>
                請輸入要查詢的訂單:<input type="text">
            </div>
        `,
    },)
    Vue.component('good', {
        template: `
            <div>
                <h1>商品內容</h1>
            </div>
        `,
    },)

    var vm = new Vue({
        el: '#app',
        data: {
            //默認顯示index
            who: 'index'

        },
        methods: {
            changeC(data) {
                this.who = data
            }
        }

    })
</script>
</html>

動態組件

Tags: