1. Vue生命周期钩子函数&组件&插槽.md

1. 生命周期

1.1 生命周期图

image-20220507093231582

1.2 生命周期函数
钩子函数描述
beforeCreate创建Vue实例之前调用(没有任何的数据)
created创建Vue实例成功后调用(可以在此处发送异步请求后端数据)
beforeMount渲染DOM之前调用
mounted渲染DOM之后调用
beforeUpdate重新渲染之前调用(数据更新等操作时,控制DOM重新渲染)
updated重新渲染完成之后调用
beforeDestroy销毁之前调用
destroyed销毁之后调用
created: 向后端发请求拿数据,发送ajax请求

mounted: 定时任务, 延迟任务
beforeDestroy: 定时任务关闭, 销毁一些操作
1.3 创建/挂载/更新
create创建: 定义一个对象或组件.
// 创建Vue对象, 也被称为根组件
var app = new Vue({
	el: '',
	data: {name: 'kid'},
	methods: { func(){} }
})
组件定义的变量, 方法只能给自己的模板使用.
// 创建组件:
Vue.component('组件名', {
    // 模板
	template:`
	<div>
	{{ name }}
	</div>`,
    // data函数中返回自定义对象, 自定义对象中定义使用的变量
	data(){
        return {
			name: 'kid'
        }
	},
    // 方法
    methods: {
        func(){}
    }
})
mount挂载: 将Vue或组件放置到页面, 让页面能够使用.
// 对象的挂载
<div id='app'> xxx </div>

var app = new Vue({
	el: 'app',
    ...
}
// 组件挂载
<组件名></组件名>

Vue.component('组件名', ...)
update更新: 更新数据会重新渲染, (并不是所有的数据改变都会重新渲染!!!)
1.4 钩子函数测试
Vue对象没法看见效果过程, 定义一个组件来测试.
钩子函数与参数同级.
console.group()分组展示
console.groupEnd() 结束分组

this.属性   查看当前对象data属性中定义属性值.
this.$属性, 查看当前对象的属性, 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue生命周期</title>
    <script src="js/vue.js"></script>
</head>
<body>

<div id="app">
    <button @click="headerClick">组件(添加/删除)</button>
    <model1 v-if="is_show">展示组件</model1>
</div>
</body>
<script>
    // 定义Vue对象 --作用--> 调用组件
    var vm = new Vue({
        el: '#app',
        data: {
            // 组件的开关
            is_show: false,
        },
        // 组件绑定的点击事件
        methods: {
            headerClick() {
                // 一点开, 再点关
                this.is_show = !this.is_show
            }
        }
    })

    // 定义组件
    Vue.component('model1',
        {
            template: `
              <div>
              <p>我的名字: {{ name }}</p>
              <p>
                <button @click="vary">点击修改名字</button>
              </p>
              </div>
            `,

            // 定义组件的变量
            data() {
                return {
                    name: 'kid'

                }
            },

            // 定义组件的方法
            methods: {
                vary() {
                    this.name = 'qq'
                },


            },
             beforeCreate() {
                    console.group('当前状态:beforeCreate')
                    console.log('当前el状态:', this.$el)
                    console.log('当前data状态:', this.$data)
                    console.log('当前name状态:', this.name)
                    console.groupEnd()
                },
                created() {
                    console.group('当前状态:created')
                    console.log('当前el状态:', this.$el)
                    console.log('当前data状态:', this.$data)
                    console.log('当前name状态:', this.name)
                    console.groupEnd()
                },
                beforeMount() {
                    console.group('当前状态:beforeMount')
                    console.log('当前el状态:', this.$el)
                    console.log('当前data状态:', this.$data)
                    console.log('当前name状态:', this.name)
                    console.groupEnd()
                },
                mounted() {
                    console.group('当前状态:mounted')
                    console.log('当前el状态:', this.$el)
                    console.log('当前data状态:', this.$data)
                    console.log('当前name状态:', this.name)
                    console.groupEnd()

                },
                beforeUpdate() {
                    console.group('当前状态:beforeUpdate')
                    console.log('当前el状态:', this.$el)
                    console.log('当前data状态:', this.$data)
                    console.log('当前name状态:', this.name)
                    console.groupEnd()
                },
                updated() {
                    console.group('当前状态:updated')
                    console.log('当前el状态:', this.$el)
                    console.log('当前data状态:', this.$data)
                    console.log('当前name状态:', this.name)
                    console.groupEnd()
                },
                beforeDestroy() {
                    console.group('当前状态:beforeDestroy')
                    console.log('当前el状态:', this.$el)
                    console.log('当前data状态:', this.$data)
                    console.log('当前name状态:', this.name)
                    console.groupEnd()
                },
                destroyed() {
                    console.group('当前状态:destroyed')
                    console.log('当前el状态:', this.$el)
                    console.log('当前data状态:', this.$data)
                    console.log('当前name状态:', this.name)
                    console.groupEnd() 
                },
        }
    )
</script>
</html>
添加组件展示:

2022-05-07_00542

组件数据更新:

2022-05-07_00543

没建任务, 没有任务销毁, 看不到实际的效果.

2022-05-07_00544

1.5 创建任务销毁任务
1. mounted钩子函数中创建任务
2. beforeDestroy钩子函数重销毁创建的任务

setInterval: 定时执行,每秒钟打印一下信息.

组件销毁, 清理定时器
clearInterval(this.f)
this.f = null
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue生命周期</title>
    <script src="js/vue.js"></script>
</head>
<body>

<div id="app">
    <button @click="headerClick">组件(添加/删除)</button>
    <model1 v-if="is_show">展示组件</model1>
</div>
</body>
<script>
    // 定义Vue对象 --作用--> 调用组件
    var vm = new Vue({
        el: '#app',
        data: {
            // 组件的开关
            is_show: false,
        },
        // 组件绑定的点击事件
        methods: {
            headerClick() {
                // 一点开, 再点关
                this.is_show = !this.is_show
            }
        }
    })

    // 定义组件
    Vue.component('model1',
        {
            template: `
              <div>{{text}}</div>
            `,

            // 定义组件的变量
            data() {
                return {
                    // 定义一个变量接收函数
                    func: null,
                    text: '打印信息中'
                }
            },

            // 定义一个定时任务
            mounted() {
                //  匿名箭头函数
                this.func = setInterval(()=>{
                    console.log('hello word!')
                }, 1000)

            },

            // 销毁定时任务
            beforeDestroy() {
                // 清除定时任务
                clearInterval(this.func)
                // 清除值
                this.func = null
            },
        }
    )
</script>
</html>

GIF 2022-5-7 12-28-51

2. Vue与后端交互

在页面渲染之前, created钩子函数向后端发送请求, 获取数据, 再将data的自定义对象的属性值修改.
方式一: jquery的ajax方法发送请求(基本不用了)

方式二: js官方提供的fetch方法(XMLHttpRequest)(官方的, 用的也少)

方式三: axios第三方, 做ajax请求(目录使用较多)
2.1 后端服务
* 1. 安装flask
 pip install flask
* 2. 创建一个flask项目
from flask import Flask, make_response, jsonify

app = Flask(__name__)


@app.route('/')
def index():
    # 返回json格式的数据
    obj = make_response(jsonify({'name': 'kid', 'age': 18}))
    # 跨域问题
    obj.headers['Access-Control-Allow-Origin'] = '*'
    return obj


if __name__ == '__main__':
    app.run()
2.2 ajax
在钩子函数created中发送jquery的ajax请求获取数据, 之后修改data的属性值.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue与后端交互</title>
    <!--导入vue-->
    <script src="js/vue.js"></script>
    <!--导入jquery-->
    <script src="js/jquery-3.6.0.min.js"></script>

</head>
<body>

<div id="app">
    <p>我的名字:{{name}}</p>
    <p>我的年龄:{{age}}</p>
</div>
</body>
<script>
    // 定义Vue对象
    var vm = new Vue({
        el: '#app',
        data: {
            name: '',
            age: ''
        },
        created() {
            // 向后端发送ajax请求
            $.ajax({
                url: 'http://127.0.0.1:5000',
                type: 'get',
                // 回调函数使用箭头函数, 不产生自己的this.
                success: args => {
                    this.name = args.name
                    this.age = args.age
                }
            })
        }
    })

</script>
</html>
先开启flask服务

image-20220507164530564

打开页面

image-20220507164722850

2.3 fetch
在钩子函数created中发送js原生的fetch请求获取数据, 之后修改data的属性值.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue与后端交互</title>
    <!--导入vue-->
    <script src="js/vue.js"></script>
    <!--导入jquery-->
    <script src="js/jquery-3.6.0.min.js"></script>

</head>
<body>

<div id="app">
    <p>我的名字:{{name}}</p>
    <p>我的年龄:{{age}}</p>
</div>
</body>
<script>
    // 定义Vue对象 
    var vm = new Vue({
        el: '#app',
        data: {
            name: '',
            age: ''
        },
        created() {
            // 向后端发送请求
            fetch('http://127.0.0.1:5000/').then(res => res.json()).then(res => {
                console.log(res)
                this.name = res.name
                this.age = res.age
            })
        }
    })
</script>
</html>
2.4 axios
在钩子函数created中发送ajax请求获取数据, 之后修改data的属性值.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue与后端交互</title>
    <!--导入vue-->
    <script src="js/vue.js"></script>
    <!--导入jquery-->
    <script src="js/jquery-3.6.0.min.js"></script>
    <!--导入axios-->
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>

</head>
<body>

<div id="app">
    <p>我的名字:{{name}}</p>
    <p>我的年龄:{{age}}</p>
</div>
</body>
<script>
    // 定义Vue对象
    var vm = new Vue({
        el: '#app',
        data: {
            name: '',
            age: ''
        },
        created() {
            // 向后端发送请求
            axios.get('http://127.0.0.1:5000').then(data => {
                // 数据放置返回值的data的data属性中
                console.log(data.data)
                this.name = data.data.name
                this.age = data.data.age
            })
        }
    })
</script>
</html>
2.5 练习
获取一些电影的数据
地址: https://m.maizuo.com/v5/?co=mzmovie#/city
获取服务器返回的给页面的数据.

image-20220507172015425

将数据复制到项目的Movie.json文件中

image-20220507172131282

from flask import Flask, make_response, jsonify

app = Flask(__name__)


@app.route('/films')
def films():
    # 跨域问题
    import json
    with open('./Movie.json', mode='r', encoding='utf-8') as f:
        # 文件时json格式的字符串, 反序列化拿到字典
        res = json.load(f)
    # 返回json格式数据, JsonResponse
    obj = make_response(jsonify(res))
    # 解决跨域问题
    obj.headers['Access-Control-Allow-Origin'] = '*'
    return obj


if __name__ == '__main__':
    app.run()
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue与后端交互</title>
    <!--导入vue-->
    <script src="js/vue.js"></script>
    <!--导入jquery-->
    <script src="js/jquery-3.6.0.min.js"></script>
    <!--导入axios-->
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>

</head>
<body>

<div id="app">
    <h1>电影列表</h1>
    <ul>
        <li v-for="obj in movie">
            <p>电影名称: {{obj.name}}</p>
            <img :src="obj.poster" alt="" height="100px">
            <p>介绍:{{obj.synopsis}}</p>
            <hr>
        </li>
    </ul>
</div>
</body>
<script>
    // 定义Vue对象 
    var vm = new Vue({
        el: '#app',
        data: {
            // 等下用于存储 电影的列表数据
            movie: '',

        },
        created() {
            // 向后端发送请求
            axios.get('http://127.0.0.1:5000/films').then(data => {
                // 数据放置返回值的data的data属性的data属性的films属性中, 烦死了
                console.log(data.data.data.films)

                // 数据是一个数组套对象
                this.movie = data.data.data.films
            })
        }
    })
</script>
</html>

image-20220507182630210

3. 计算属性

3.1 引入1
实现名字首字母大写
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>计算属性</title>
    <!--导入vue-->
    <script src="js/vue.js"></script>

</head>
<body>

<div id="app">
    输入英文: <input type="text" v-model="text"> -->
    <!-- text.substring(0, 1)截取字符串第一个值,  toUpperCase转大写, text.substring(1)截取索引1之后的所有值-->
    {{text.substring(0, 1).toUpperCase() + text.substring(1)}}
</div>
</body>
<script>

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

image-20220507213504174

不推荐在插值中写过长的代码, 将代码打包到methods的函数中.
3.2 引入2
实现名字首字母大写
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>计算属性</title>
    <!--导入vue-->
    <script src="js/vue.js"></script>

</head>
<body>

<div id="app">
    输入英文: <input type="text" v-model="text"> -->
    {{Capitalize()}}
</div>
</body>
<script>

    var vm = new Vue({
        el: '#app',
        data: {
            text: '',
        },

        methods: {
            Capitalize() {
                console.log('Capitalize函数被触发')
                return this.text.substring(0, 1).toUpperCase() + this.text.substring(1)

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

GIF 2022-5-7 21-52-41

3.3 引入3
写一个input框, 使用v-model双向绑定一个数据.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>计算属性</title>
    <!--导入vue-->
    <script src="js/vue.js"></script>

</head>
<body>

<div id="app">

    <p>
        输入英文: <input type="text" v-model="text"> -->
        {{Capitalize()}}
    </p>

    <p>
        输入英文(没有绑定函数): <input type="text" v-model="text2"> --> {{text2}}
    </p>
</div>
</body>
<script>

    var vm = new Vue({
        el: '#app',
        data: {
            text: '',
            text2: '',
        },

        methods: {
            Capitalize() {
                console.log('Capitalize函数被触发')
                return this.text.substring(0, 1).toUpperCase() + this.text.substring(1)
            }
        }
    })
</script>
</html>

GIF 2022-5-7 22-02-00

页面中只要数据发生变化了,  methods 中定义的函数, 也会重新触发. 这样就会消耗不必要的资源.
3.4 计算属性
computed-->把方法变成属性-->延缓计算
在页面中直接使用函数, 页面只要刷新, 函数就会重新运行,使用计算属性
只有当前函数使用的变量发生变化时, 才重新运算.
计算属性只有在它的相关依赖发生改变时才会重新求值.
计算属性在computed中定义, 写法与函数一样.  调用不需要加().
函数需要返回一个值, 这个值就是属性的值, 调用数据时展示.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>计算属性</title>
    <!--导入vue-->
    <script src="js/vue.js"></script>

</head>
<body>

<div id="app">

    <p>
        输入英文: <input type="text" v-model="text"> -->
        {{Capitalize}}
    </p>

    <p>
        输入框(没有绑定函数): <input type="text" v-model="text2"> --> {{text2}}
    </p>
</div>
</body>
<script>

    var vm = new Vue({
        el: '#app',
        data: {
            text: '',
            text2: '',
        },


        computed: {
            Capitalize() {
                console.log('Capitalize函数被触发')
                return this.text.substring(0, 1).toUpperCase() + this.text.substring(1)
            }
        }
    })
</script>
</html>

GIF 2022-5-7 22-12-17

3.5 过滤案例
使用计算属性写过滤案例.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>计算属性</title>
    <!--导入vue-->
    <script src="js/vue.js"></script>
</head>
<body>

<div id="app">
    <input type="text" v-model="test">
    <ul>
        <li v-for="i in filter_array">{{i}}</li>
    </ul>
</div>
</body>
<script>

    var vm = new Vue({
        el: '#app',
        data: {
            // 过滤的的列表
            array1: ['a', 'ab', 'abc', 'x', 'xy', 'xyz'],
            test: ''
        },

        // 过滤列表
        computed: {
            filter_array() {
                console.log('计算属性被触发了!')
                var array2 = this.array1.filter(value => {
                    return value.indexOf(this.test) > -1
                })
                return array2
            }
        }
    })
</script>
</html>
计算属性默认触发以, 遍历数组的值判断值中是否有'', 返回0, 0 > -1, 返回一个完整的列表.

2022-05-07_00551

GIF 2022-5-7 22-46-12

4. 监听属性

watch: 监听属性只要监听的变量发生变化,就会执行方法.
监听一个属性, 当它的值发生变化, 触发绑定的函数.
监听属性在Vue对象的watch属性中定义.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>监听属性</title>
    <!--导入vue-->
    <script src="js/vue.js"></script>
</head>
<body>

<div id="app">
    <input type="text" v-model="test"> --> {{test}}
</div>
</body>
<script>

    var vm = new Vue({
        el: '#app',
        data: {
            test: ''
        },

        // 监听属性
        watch: {
            test: function (){
                console.log('触发侦听属性')
            }
        }
    })
</script>
</html>

GIF 2022-5-7 23-09-27

5. 组件化开发

组件: 将html, css(样式), js(逻辑)封装成一个组件, 在使用的的使用可以直接调用即可.

组件只能够在Vue对象el绑定的标签中使用, 每个组件的数据都是独立的.
全局组件: 可以在任意位置中调用, 可以局部中调用全局组件.
局部组件: 只能局部使用.
5.1 全局组件
全局组件:Vue.component()
组件有自己的html,css,js,相互不影响
template 一定要放在一个标签中
data必须是函数data(){retrun {} }
全局组件定义格式:
Vue.('组件名',
    {
    	// 定义模板, 模板只能管理一个标签. `<div> </div> 这样是不行的 <div> </div>`
		template:``,
    	// 定义模板使用的数据
    	data:{
            return {
            // 定义数据
        	}
        },
        //  定义方法
        methods: {},
})

最后定义一个vue对象.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>全局组件</title>
    <!--导入vue-->
    <script src="js/vue.js"></script>
</head>
<body>
<div id="box">
    <xx1></xx1>
    <xx2></xx2>
</div>

<xx1></xx1>
<script>

    // 定义局部组件, 组件名不能和html自带的标签重名
    // 组件1
    Vue.component('xx1',
        {
            // 定义模板, 只能管理一个标签, 可以在标签中嵌套标签
            template: `
              <div>
                  <p style="size: 30px; color: aqua">全局组件</p>
                  <p>我的名字:{{ name }}</p>
                  <p>
                    <button @click="func">打开弹框1</button>
                  </p>
              </div>
            `,
            // 定义模板使用的数据, data是一个函数, 在函数中返回模板需要使用的数据
            data() {
                return {
                    name: 'kid'
                }
            },

            // 定义方法
            methods: {
                func() {
                    alert('我的弹框!1')
                }
            }
        }
    )

    // 组件2
    Vue.component('xx2',
        {
            // 定义模板, 只能管理一个标签, 可以在标签中嵌套标签
            template: `
              <div>
                  <p style="size: 30px; color: red">全局组件</p>
                  <p>我的名字:{{ name }}</p>
                  <p>
                    <button @click="func">打开弹框2</button>
                  </p>
              </div>
            `,
            // 定义模板使用的数据, data是一个函数, 在函数中返回模板需要使用的数据
            data() {
                return {
                    name: 'qq'
                }
            },

            // 定义方法
            methods: {
                func() {
                    alert('我的弹框!2')
                }
            }
        }
    )

    var vm = new Vue({
        el: '#box',
        data: {},
    })
</script>
</body>
</html>
5.2 局部组件
局部组件: 写在组件内部 Vue.components中, 格式与全局组件一致.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>局部组件</title>
    <!--导入vue-->
    <script src="js/vue.js"></script>
</head>
<body>
<div id="box">
    <xx1></xx1>
    <xx2></xx2>
</div>
<script>
    
    var vm = new Vue({
        el: '#box',
        data: {},
        components:{
            // 组件1
            'xx1': {
            // 定义模板, 只能管理一个标签, 可以在标签中嵌套标签
            template: `
              <div>
                  <p style="size: 30px; color: aqua">全局组件</p>
                  <p>我的名字:{{ name }}</p>
                  <p>
                    <button @click="func">打开弹框1</button>
                  </p>
              </div>
            `,
            // 定义模板使用的数据, data是一个函数, 在函数中返回模板需要使用的数据
            data() {
                return {
                    name: 'kid'
                }
            },

            // 定义方法
            methods: {
                func() {
                    alert('我的弹框!1')
                }
            }
        },
            // 组件2
            'xx2': {
            // 定义模板, 只能管理一个标签, 可以在标签中嵌套标签
            template: `
              <div>
                  <p style="size: 30px; color: red">全局组件</p>
                  <p>我的名字:{{ name }}</p>
                  <p>
                    <button @click="func">打开弹框2</button>
                  </p>
              </div>
            `,
            // 定义模板使用的数据, data是一个函数, 在函数中返回模板需要使用的数据
            data() {
                return {
                    name: 'qq'
                }
            },

            // 定义方法
            methods: {
                func() {
                    alert('我的弹框!2')
                }
            }
        }
        }
    })
</script>
</body>
</html>

6. 组件数据传递

通过自定义属性:父传子-自定义的属性写在自定义的组件上, 自定义组件 --> props:['自定义属性名']
通过自定义事件:子传父-子中调用this.$emit('自定义事件名', 参数1, ...) -->触发写在定义组件上的 
@自定义事件名='函数'--> 函数执行(父组件)

ref属性:
放在普通标签--通过this.$refs.属性值-->原生dom
放在组件上--通过this.$refs.属性值--> 当前组价对象--> 拿到组件中的值, 执行组件中的方法
6.1 父组件传值给子组件
父组件传值给子组件
   1.1 在父组件的data中定义数据
   1.2 使用子组件, 为子组定义一个自定义属性, 使用属性赋值的方式将父组件变量赋值自定义属性.
   1.3 为子组件中的props属性定义一个数组, 组件中以字符串形式存放上面接收变量的自定义属性名.
   1.4 在子组件中便可以通过插值语法, 属性赋值语法调用自定义属性, 得到父组件传递的值. 
       一次传递一个, 创建多个就把值封装成一个对象.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>数据传递</title>
    <!--导入vue-->
    <script src="js/vue.js"></script>
</head>
<body>
<div id="box">
    <p>父组件: <input type="text" v-model="text"> --> {{text}}</p>
    <!--自定义一个属性, 保证属性名和props中的属性名和变量名一致即可-->
    <xx1 :my_text="text"></xx1>
</div>

<script>

    // 定义局部组件, 组件名不能和html自带的标签重名
    // 组件1
    Vue.component('xx1',
        {
            // 定义模板, 只能管理一个标签, 可以在标签中嵌套标签
            template: `
              <div>
              <p style="size: 30px; color: aqua">子组件:{{ my_text }}</p>
              </div>
            `,

            // 保证属性名和props中的属性名和变量名一致即可
            props: ['my_text']
        }
    )

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

2022-05-08_00554

6.2 子组件传值给父组件
子组件传值给父组件
	1.1 子组件中, 使用v-model对数据进行双向绑定, 在设置一个提交按钮
	1.2 为按键绑定一个点击事件, 在点击事件中使用 this.$emit('事件名', 参数1..)触发父组件的事件
	1.3 使用子组件, 为子组件标签定义一个自定义事件并绑定一个父组件的方法.
	1.4 在父组件中使用的参数及是子组件的数据, 通过该数据改变父组件的数据.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>数据传递</title>
    <!--导入vue-->
    <script src="js/vue.js"></script>
</head>
<body>
<div id="box">
    <xx1 @transfer="update_text"></xx1>
    <hr>
    <p>父组件</p>
    <p>接收的值:{{text}}</p>
</div>

<script>

    // 定义局部组件, 组件名不能和html自带的标签重名
    // 组件1
    Vue.component('xx1',
        {
            template: `
              <div>
                  <p>子组件</p>
                  <p><input type="text" v-model="text"> --> {{ text }}</p>
                  <p>
                    <button @click="text_submit">提交数据给父组件</button>
                  </p>
              </div>
            `,

            data() {
                return {
                    text: ''
                }
            },
            // 定义子组件方法, 触发父组件的方法
            methods: {
                text_submit() {
                    // this.$emit 触发父组件的事件, ('自定义事件名', 参数1, ...)
                    this.$emit('transfer', this.text)
                }
            }

        }
    )
    var vm = new Vue({
        el: '#box',
        data: {
            text: '',
        },
        // 定义父组件方法
        methods: {
            // 更新数据, 接收参数
            update_text(text) {
                // 将参数作为更新的值
                this.text = text
            }
        }
    })
</script>
</body>
</html>

2022-05-08_00556

GIF 2022-5-8 13-17-01

6.3 ref属性
1. 在标签中定义ref属性, 该属性是Vue提供的. ref='键'
2. 在定义之后, 该标签被打包成一个对象的值.  ref='键: 标签对象{属性: 值, ..}'
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ref属性</title>
    <!--导入vue-->
    <script src="js/vue.js"></script>
</head>
<body>
<div id="box">
    <input type="text" ref="my_input" value="123">
    <button @click="button_c">按键</button>
</div>

<script>

    var vm = new Vue({
        el: '#box',
        methods: {
            button_c() {
                // this.$refs, 查看所有标签中定义了ref属性的标签对象, 键为ref的值, 值为定义了ref属性的标签 {my_input: input}
                // 标签对象中存放了该标签所有的属性与值 input对象{属性 :值, ...}
                console.log(this.$refs)  // {my_input: input}
                console.log(this.$refs.my_input)  // <input type="text" value="123"> 默认展示定义的属性与值, 没有展示的也可以直接取到
                console.log(this.$refs.my_input.value)
            }
        }
    })
</script>
</body>
</html>

2022-05-08_00557

input中存放了所有的属性, 默认展示标签中定义的属性与值.
6.4 ref数据传递
ref定义在子组件中, 那个就可以拿到整个子组件对象. 相当于父组打开了一条通往子组件通道.
子组件没打打开父组件的通道.拿不到Vue对象.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ref属性</title>
    <!--导入vue-->
    <script src="js/vue.js"></script>
</head>
<body>
<div id="box">
    <!-- 子组件 -->
    <Subassembly ref="my_subassembly"></Subassembly>
    <hr>
    <!-- 父组件 -->
    <button @click="button_c">按键</button>
</div>

<script>
    Vue.component('Subassembly', {
            template: `
              <p>子组件展示的信息:{{ text }}</p>
            `,
            data() {
                return {
                    text: '子组件'
                }
            },

            methods: {
                print_text() {
                    console.log('子组件的方法!')
                }
            }
        }
    )
    var vm = new Vue({
        el: '#box',
        methods: {
            button_c() {
                // 在父组件拿到子组件对象
                let my_subassembly = this.$refs.my_subassembly
                console.log(my_subassembly)

                // 修改子组件中的值 子组件对象.data中定义的属性
                my_subassembly.text = '你好啊'

                // 调用子组件中的方法 子组件对象.methods中定义的方法
                my_subassembly.print_text()
            }
        }
    })
</script>
</body>
</html>

2022-05-08_00558

6.4 $on的使用
$on用于监听当前实例对象的自定义事件, 事件可以由vm.$emit触发.
vm.$emit('事件名', 参数1, ...)
$on('事件名', 函数(参数1, ...))
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="js/vue.js"></script>
</head>
<body>
<div id="box">
    <module1></module1>
    <module2></module2>
</div>
</body>
<script>
    // 1. 定义一个vue对象
    var bus = new Vue()

    // 定义组件1
    Vue.component('module1',
        {template:`<div>发送信息:<input type="text" v-model="text"> <button @click="Click1">提交</button></div>`,
        data(){ return {text: ''}},
        methods:{Click1(){bus.$emit('submit', this.text)}}
        })

    Vue.component('module2',{
        template: `<div>接收信息:{{text}}</div>`,
        data(){return{ text: ''}},
        mounted(){bus.$on('submit', (args)=>{this.text = args})}
    })

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

image-20220508191023877

7. 动态组件

多个组件切换, 通过动态组件的:is来决定显示哪个组件
1. 定义对个组件
2. component标签中 :is的值是那个组件就会展示那个组件.
<component :is="sho"></component>
3. 通过动态改变sho的值切换使用的组件
menu_Zh = {
    'home':
        '主页', 'order':
        '订单', 'commodity':
        '商品'
}

for (i in menu_Zh) {
    console.log(i, typeof i)
    console.log(menu_Zh.i)  // 遍历对象, 这样是取不出值的 menu_Zh.home 与 menu_Zh.'home' 是不一样的
    console.log(menu_Zh[i])
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>动态组件</title>
    <!--导入vue-->
    <script src="js/vue.js"></script>
</head>
<body>
<div id="box">
    <ul>
        <!-- 删除无序列表的项目符号  横向排序-->
        <li style=" list-style-type:none; display:inline;" v-for="i in menu_list"
            @click="ClickA(i)"> {{menu_Zh[i]}}
        </li>
    </ul>

    <!--展示的组件-->
    <component :is="sho"></component>
</div>

<script>
    // 定义三个组件
    Vue.component('home', {
        template: `
                <div style="height: 400px; width: 800px; background-color: aqua">
                    <p>首页内容</p>
                </div>
            `
    })

    Vue.component('order', {
        template: `
                <div style="height: 400px; width: 800px; background-color: fuchsia">
                    <p>订单内容</p>
                </div>
            `
    })

    Vue.component('commodity', {
        template: `
                <div style="height: 400px; width: 800px; background-color: orange">
                    <p>商品内容</p>
                </div>
            `
    })

    var vm = new Vue({
        el: '#box',
        data: {
            menu_list: ['home', 'order', 'commodity'],
            menu_Zh: {'home': '主页', 'order': '订单', 'commodity': '商品'},
            sho: 'home'
        },
        //
        methods: {
            ClickA(i) {
                //   首页  订单 商品
                this.sho = i
            }
        }
    })
</script>
</body>
</html>

GIF 2022-5-8 15-54-16

8. keep-alive

keep-alive: 组件切换的时候数据不销毁.
在页面切换的时候, 之前页面中输入的信息不会被保存. 
使用keep-alive标签, 包裹需要要保留信息的标签, 输入的值再切换页面会被保留.

GIF 2022-5-8 15-58-59

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ref属性</title>
    <!--导入vue-->
    <script src="js/vue.js"></script>
</head>
<body>
<div id="box">
    <ul>
        <!-- 删除无序列表的项目符号  横向排序-->
        <li style=" list-style-type:none; display:inline;" v-for="i in menu_list"
            @click="ClickA(i)"> {{menu_Zh[i]}}
        </li>
    </ul>

    <!--展示的组件-->
    <keep-alive>
        <component :is="sho"></component>
    </keep-alive>
</div>

<script>
    // 定义三个组件
    Vue.component('home', {
        template: `
                <div style="height: 400px; width: 800px; background-color: aqua">
                    <p>首页内容</p>
                    <input type="text" style="margin-left: 30px ">
                </div>
            `
    })

    Vue.component('order', {
        template: `
                <div style="height: 400px; width: 800px; background-color: fuchsia">
                    <p>订单内容</p>
                </div>
            `
    })

    Vue.component('commodity', {
        template: `
                <div style="height: 400px; width: 800px; background-color: orange">
                    <p>商品内容</p>
                </div>
            `
    })

    var vm = new Vue({
        el: '#box',
        data: {
            menu_list: ['home', 'order', 'commodity'],
            menu_Zh: {'home': '主页', 'order': '订单', 'commodity': '商品'},
            sho: 'home'
        },
        //
        methods: {
            ClickA(i) {
                //   首页  订单 商品
                this.sho = i
            }
        }

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

GIF 2022-5-8 15-59-48

9. 插槽

<组件>写内容</组件> --> 内容无效
组件中定义插槽 --> 内容替换到插槽中
具名插槽 --> 给插槽起名字--> 使用的时候, 指定替换哪个插槽的内容
9.1 插槽的使用
自定义的组件在使用的时候, 标签中写内容是没有作用的.
插槽: 在组件的模板中是定义<slot>插槽标签, 使用组件标签中时写的内容会替换<slot>标签.
插槽的位置很重要, 依据插槽的位置替换内容.
<xxx 子组件> 
	<xx></xx>
</xxx 子组件>

组件模板中
`
	<slot>	</slot>
`
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>插槽</title>
    <!--导入vue-->
    <script src="js/vue.js"></script>
</head>
<body>
<div id="box">
    <Subassembly>
        <p>账户: <input type="text"></p>
        <p>密码: <input type="text"></p>
    </Subassembly>
</div>

<script>

    Vue.component('Subassembly', {
        template: `
            <div>
                 <h1>子组件</h1>
                 <slot></slot>
            </div>
            `
    })

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

image-20220508161601903

9.2 具名插槽
在子组件的模板中可以定义多个插槽, 为了区分使用, 可以为插槽起名字.
在使用子组件标签的使用, 内容指定使用的插槽.
<xxx 子组件> 
	<xx slot='指定名称'></xx>
</xxx 子组件>

组件模板中
`
	<slot name='起名字'>	</slot>
`
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>插槽</title>
    <!--导入vue-->
    <script src="js/vue.js"></script>
</head>
<body>
<div id="box">
    <Subassembly>
        <div slot="a">
            <p>账户: <input type="text"></p>
        </div>
        <div slot="b">
            <p>密码: <input type="text"></p>
        </div>

    </Subassembly>
</div>

<script>

    Vue.component('Subassembly', {
        template: `
            <div>
                 <slot name="a"></slot>
                 <h1>子组件</h1>
                 <slot name="b"></slot>
            </div>
            `
    })

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

image-20220508161934594

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值