Vue 组件实战

2022-05-09 18:48:42 浏览数 (2)

目录

  • Vue 组件
    • axios实现数据请求
    • 计算属性
      • 案例一:首字母大写
      • 案例二:过滤案例
    • 监听属性
    • 局部组件
    • 全局组件
    • 组件通信之父传子
    • 组件通信之子传父
    • ref属性(组件间通信)
      • 普通标签使用
      • 组件使用ref属性
    • 事件总线(不常用)
    • 动态组件和keep-alive

Vue 组件

axios实现数据请求

代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./js/vue.js"></script>
    <script src="https://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('http://127.0.0.1:5000/films').then(res => {
                console.log(res.data)
                this.films_list=res.data.data.films
            })

        }
    })
</script>
</html>
代码语言:javascript复制
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()

计算属性

我们可以通过计算属性computed来缓存计算,什么意思呢?

在Vue中我们可以使用插值来展示数据,插值的普通函数,只要页面一刷新,函数就会重新运算,不管和函数有关没关的值都会变,函数也会重新计算,导致运行效率降低;

那么我们可以将自定义函数写在computed中来控制,把函数当成属性来用,调用不需要加括号,只有这个函数使用的属性(变量)发生变化,函数才重新运算,这样做可以减轻压力,减少资源浪费

案例一:首字母大写

代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>计算属性</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://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不相关

案例二:过滤案例

代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>过滤案例</title>
    <script src="https://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>

监听属性

watch来设置监听属性,当mytext发生变化,就会执行和mytext绑定的函数方法

代码语言:javascript复制
<!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内使用

代码语言:javascript复制
<!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范围内

代码语言:javascript复制
<!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自定义属性来实现,比如如下例子:

代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://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('自定义事件',参数)来实现

代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://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进行操作设置等,如下示例:

代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://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='https://img0.baidu.com/it/u=3608430476,1945954109&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=494'
            }
        }
    })
</script>
</html>

组件使用ref属性

ref属性,如果放在组件上,就是当前组件对象

代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://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>

事件总线(不常用)

代码语言:javascript复制
<!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标签实现组件不销毁,保留原来输入的内容

代码语言:javascript复制
<!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>

0 人点赞