【前端框架】Vue中你必须要知道的基础语法~

学习一个框架,先去使用其中的知识,如果其中有不会的东西在去补充一些理论,然后再通过一些实践去巩固之前的实践和理论经验,这样最终才能真正掌握一门框架的知识。

  1. 先使用Vue(其中可能会有很多不同的地方)
  2. 再去补充其中的理论知识
  3. 最后再用一个实战项目来巩固所学知识

初识Vue

我的第一个Vue案例

不用安装Vue,直接使用Vue提供的cdn,https://unpkg.com/vue@next就可以直接编写vue代码了。

注意:如果cdn不够快,这可以使用这个(我在网上找的)

    <script src="https://unpkg.com/vue@next"></script>
    <script src="https://unpkg.com/vue-router@next"></script>
    <script src="https://unpkg.com/vuex@next"></script>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vant@next/lib/index.css"/>
    <script src="https://cdn.jsdelivr.net/npm/vant@next/lib/vant.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="https://unpkg.com/vue@next"></script>
    <title>Hello Vue</title>
</head>
<body>
    <div id="root"></div>
</body>
<script type="text/javascript">
    Vue.createApp({
        data() {
            return {
                content: 1
            }
        },
        mounted() {
            setInterval(() => {
                this.$data.content += 1;
            }, 1000)
        },
        template: '<div>hello world, {{content}}</div>'
    }).mount('#root');
</script>
</html>
  • template:需要渲染的内容
  • data()函数:返回需要的数据
  • mounted()函数:当页面加载完成后会自动执行的函数
  • .mount(‘#root’):需要将渲染的渲染的内容挂载到哪一个节点后面
  • {{}}:括号中的内容可以进行数据解析,这叫做差值表达式

初试v-on点击绑定事件

  • 功能:点击按钮可以反转hello world字符串
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="https://unpkg.com/vue@next"></script>
    <title>Hello Vue</title>
</head>
<body>
    <div id="root"></div>
</body>
<script type="text/javascript">

    Vue.createApp({
        data() {
            return {
                content: 'hello world',
            }
        },
        methods: {
            handleBtnClick() {
                this.content = this.content.split('').reverse().join('');
            }
        },
        template: `
            <div>
                {{content}}
                <button v-on:click="handleBtnClick">反转</button>
            </div>
        `
    }).mount('#root');
</script>
</html>

初试v-if

  • 功能:点击按钮可以显示或隐藏hello world字符串
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="https://unpkg.com/vue@next"></script>
    <title>Hello Vue</title>
</head>
<body>
    <div id="root"></div>
</body>
<script type="text/javascript">
    Vue.createApp({
        data() {
            return { show: true }
        },
        methods: {
            handleBtnClick() {
                this.show = !this.show;
            }
        },
        template: `
            <div>
                <span v-if="show">hello world</span>
                <button v-on:click="handleBtnClick">显示/隐藏</button>
            </div>
        `
    }).mount('#root');
</script>
</html>

v-for循环,v-model双向绑定和v-bind初试

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="https://unpkg.com/vue@next"></script>
    <title>Hello Vue</title>
</head>
<body>
    <div id="root"></div>
</body>
<script type="text/javascript">
    Vue.createApp({
        data() {
            return {
                list: [],
                inputValue: '',
            }
        },
        methods: {
            handleAddItem() {
                this.list.push(this.inputValue);
                this.inputValue = '';
            }
        },
        template: `
        <div>
            <input v-model="inputValue" />
            <button 
                v-on:click="handleAddItem" 
                v-bind:title="inputValue"
            > 增加</button>
            <ul>
                <li v-for="(item, index) of list">{{index}} : {{item}}</li>
            </ul>
        </div>
        `
    }).mount('#root');
</script>
</html>
  • v-model=v-bind+v-on

在表单上使用双向绑定,其实就是将inputValue和变淡的value属性值进行绑定(v-bind的作用),并且在表单提交的时候,inputValue属性值也会被提交(v-on的作用)。

  • v-bind和{{}}的区别

要想在将标签中将内容进行数据的绑定替换的话,可可以直接使用{{}}差值表达式即可。但是如果一个标签的属性要想要和一个数值绑定的话,就需要使用v-bind

v-bind的简写是:,所以加上了:之后,属性之后的""内就不是单纯的字符串了,而是可以是表达式。

组件的概念初探

其实前端中每一个模块都是一个组件,那么在vue中我们可以将一个自定义一个模块成为一个组件,以供之后的使用。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="https://unpkg.com/vue@next"></script>
    <title>Hello Vue</title>
</head>
<body>
    <div id="root"></div>
</body>
<script type="text/javascript">
    const app = Vue.createApp({
        data() {
            return {
                list: [],
                inputValue: '',
            }
        },
        methods: {
            handleAddItem() {
                this.list.push(this.inputValue);
                this.inputValue = '';
            }
        },
        template: `
        <div>
            <input v-model="inputValue" />
            <button 
                v-on:click="handleAddItem" 
                v-bind:title="inputValue"
            > 增加</button>
            <ul>
                <todo-item 
                v-for="(item, index) of list"
                v-bind:content="item"
                v-bind:index="index"
                />
            </ul>
        </div>
        `
    });
    app.component('todo-item', {
        // props就是在接收外部到当前组件中的属性,组件中可以获得这些组件的属性值
        // 本质上其实就是通过组件的标签,来获得外部对组件的传递的数据
        props: ['content', 'index'], 
        template: `
        <li>{{index}} -- {{content}}</li>
        `
    });
    app.mount('#root');
</script>
</html>

如果看不同也不要紧,这只是试用一下而已。

在做项目的时候,面向对象的语言会将项目中不同的部分拆分成不同的部分,以此可以将项目模块化,从而使得整个项目框架很清晰。

而vue中组件也是一样,我们将原来的li标签,写成了一个我们需要的组件起一个名字叫做todo-item,然后定义这个组件可以干什么。其中template就是这个组件需要渲染出的内容。

有的人觉得你在组件中又定义了一个li标签,这不和原来一样嘛,但是要注意的是,我们可以将组件中的内容定义的很复杂,这可以li标签不能替代的。所以这就是组件的好处。标签组件可以通过props来接收外部发来的数据,这样我们就可以将组件从原来的项目中抽出来,可以将其功能定义的很复杂,同时和之前的项目也有数据的关联。

Vue基础语法

本章来讲解一下vue的基础语法

Vue应用和组件的基础概念

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="https://unpkg.com/vue@next"></script>
    <title>Hello Vue</title>
</head>
<body>
    <div id="root"></div>
</body>
<script type="text/javascript">
    const app = Vue.createApp({
        data() {
            return {
                message: 'hello world',
            }
        },
        template: "<div>{{message}}</div>"
    });
    const vm = app.mount('#root');
	console.log(vm.$data.message);
</script>
</html>
  1. 在vue中,可以使用Vue.createApp()的方式来创建一个应用,并且可以存放在一个变量中。
  2. 其中的date()template都是为了设置该组件在外部前端展示的内容。
  3. 通过mount()可以将该组件挂载到一个dom元素下,并返回值是一个这个应用的根组件
  4. vue采用的是mvvm设计模式,即m->model(数据),v->view(视图),vm->(viewModel)视图数据连接层。vue的组件通过data传递数据,在template中定义展示的内容,而将两者连接起来的就是应用的根组件也是应用的视图数据连接层。
  5. 根组件可以通过$data的来获得组件的数据。

Vue中声明周期函数

8个声明周期函数:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="https://unpkg.com/vue@next"></script>
    <title>Hello Vue</title>
</head>
<body>
    <div id="root">
        <div>{{message}}!</div>
    </div>
</body>
<script type="text/javascript">
    // 生命周期函数:在某一个时刻会自动执行的函数
    const app = Vue.createApp({
        data() {
            return {
                message: 'hello world',
            }
        },
        // 在应用示例生成之前执行的函数
        beforeCreate() {
            console.log("beforeCreate");
        },
        // 在应用示例生成之后执行的函数
        created() {
            console.log("created");
        },
        // 在template内容被渲染成render函数之后,在组件被渲染到页面之前执行的函数
        beforeMount() {
            console.log(document.getElementById('root').innerHTML, "beforeMount");
        },
        // 在组件被渲染到页面之后执行的函数
        mounted() {
            console.log(document.getElementById('root').innerHTML, "mounted");
        },
        // 当数据发生变化,立即执行的函数
        beforeUpdate() {
            console.log(document.getElementById('root').innerHTML, "beforeUpdate");
        },
        // 当数据发生变化,页面重新渲染之后立即执行的函数
        updated() {
            console.log(document.getElementById('root').innerHTML, "updated");
        },
        // 在Vue应用销毁时,立即执行的函数
        beforeUnmount() {
            console.log(document.getElementById('root').innerHTML, "beforeUnmount");
        },
        // 在Vue应用销毁时,并且dom完全销毁之后,立即执行的函数
        unmount() {
            console.log(document.getElementById('root').innerHTML, "unmount");
        },
        // template: "<div>{{message}}</div>"
    });
    const vm = app.mount('#root');
    console.log(vm.$data.message);
</script>
</html>
  • 生命周期函数:在某一个时刻会自动执行的函数
    1. beforeCreate:在app示例生成之前立即执行的函数
    2. created:在app示例生成之后立即执行的函数
    3. beforeMount:在组件被转换成render函数之前,组件被渲染到页面之前执行的函数
    4. mounted:在组件被渲染到页面之后立即执行的函数
    5. beforeUpdate:当数据发生变化,立即执行的函数
    6. updated:当数据发生变化,页面重新渲染之后,立即执行的函数
    7. beforeUnmount:当app被销毁时,立即执行的函数
    8. unmount:当app被销毁时,并且dom元素被完全销毁之后立即执行的函数

注意:如果没有template的话,会默认渲染挂载元素的innerHTML,所以template中的内容也可以直接写到挂载元素的下面。

关键提炼:

  • ![[Pasted image 20220428220658.png]]
  • 生命周期函数也叫作钩子函数

常用模板语法

  • {{}}:差值表达式,括号中可以解析data中的变量。也可以解析js的表达式(注意是表达式而不是语句)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="https://unpkg.com/vue@next"></script>
    <title>Hello Vue</title>
</head>
<body>
    <div id="root"></div>
</body>
<script type="text/javascript">
    const app = Vue.createApp({
        data() {
            return {
                message: "hello world",
            }
        },
        template: "<div>{{message + ', I am student'}}</div>"
    });
    app.mount('#root');
</script>
</html>
  • v-html:可以将一个节点直接以html的方式挂载到一个节点之下
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="https://unpkg.com/vue@next"></script>
    <title>Hello Vue</title>
</head>
<body>
    <div id="root"></div>
</body>
<script type="text/javascript">
    const app = Vue.createApp({
        data() {
            return {
                message: "<strong>hello world</strong>",
            }
        },
        template: `<div v-html='message'></div>`
    });
    app.mount('#root');
</script>
</html>
  • v-bind:将一个标签的属性和数值进行绑定。(注意如果是标签的内容进行绑定的话,可以使用{{}})
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="https://unpkg.com/vue@next"></script>
    <title>Hello Vue</title>
</head>
<body>
    <div id="root"></div>
</body>
<script type="text/javascript">
    const app = Vue.createApp({
        data() {
            return {
                disable: true,
            }
        },
        template: `<input v-bind:disabled="disable" />`
    });
    app.mount('#root');
</script>
</html>
  • v-if:该标签会进行v-if中的判断
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="https://unpkg.com/vue@next"></script>
    <title>Hello Vue</title>
</head>
<body>
    <div id="root"></div>
</body>
<script type="text/javascript">
    const app = Vue.createApp({
        data() {
            return {
                message: "hello world",
                show: false,
            }
        },
        template: `<div v-if="show">{{message}}</div>`
    });
    app.mount('#root');
</script>
</html>
  • v-once:保证该组件只会被渲染一次,避免了无用的渲染来消耗性能
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="https://unpkg.com/vue@next"></script>
    <title>Hello Vue</title>
</head>
<body>
    <div id="root"></div>
</body>
<script type="text/javascript">
    const app = Vue.createApp({
        data() {
            return {
                message: "hello world",
            }
        },
        template: `<div v-once>{{message}}</div>`
    });
    const vm = app.mount('#root');
</script>
</html>
  • v-on:绑定事件
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="https://unpkg.com/vue@next"></script>
    <title>Hello Vue</title>
</head>
<body>
    <div id="root"></div>
</body>
<script type="text/javascript">
    const app = Vue.createApp({
        data() {
            return {
                message: "hello world",
            }
        },
        methods: {
            handleClick() {
                alert("finish click");
            }
        },
        template: `
            <div v-on:click="handleClick" 
            v-bind:title="message">
            {{message}}
            </div>
        `
    });
    const vm = app.mount('#root');
</script>
</html>

注意:

  • 其中v-on和v-bind有简写形式,分别用@和:来代替。
  • 标签的属性也是可以是动态变化的,即标签的动态属性,可以使用[]来绑定标签的属性
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="https://unpkg.com/vue@next"></script>
    <title>Hello Vue</title>
</head>
<body>
    <div id="root"></div>
</body>
<script type="text/javascript">
    const app = Vue.createApp({
        data() {
            return {
                message: "hello world",
                event: "click",
                name: "title"
            }
        },
        methods: {
            handleClick() {
                alert("finish click");
            }
        },
        template: `
            <div @[event]="handleClick" 
            :[name]="message">
            {{message}}
            </div>
        `
    });
    const vm = app.mount('#root');
</script>
</html>
  • 事件修饰符

如果想要将标签的默认行为取消掉的话,可以这样写:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="https://unpkg.com/vue@next"></script>
    <title>Hello Vue</title>
</head>
<body>
    <div id="root"></div>
</body>
<script type="text/javascript">
    const app = Vue.createApp({
        methods: {
            handleClick(e) {
                e.preventDefault();
            }
        },
        template: `
        <a href="http://www.baidu.com" @click="handleClick">百度一下</a>
        `
    });
    const vm = app.mount('#root');
</script>
</html>

模板语法中可以使用事件的修饰符来对事件进行修饰,通过使用prevent来修饰的话,也可以取消一个标签的默认行为。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="https://unpkg.com/vue@next"></script>
    <title>Hello Vue</title>
</head>
<body>
    <div id="root"></div>
</body>
<script type="text/javascript">
    const app = Vue.createApp({
        template: `
        <a href="http://www.baidu.com" @click.prevent>百度一下</a>
        `
    });
    const vm = app.mount('#root');
</script>
</html>

数据,方法,计算属性和侦听器

data,methods,computed,watcher

  • data:app中的this指的是app这个实例,可以根据这个this来获取data中的数据
<script type="text/javascript">
    const app = Vue.createApp({
        data() {
            return {
                message: "hello world",
            }
        },
        methods: {
            handleClick() {
                console.log(this); // 打印app实例
                console.log(this.$data.message); // hello world
                console.log(this.message); // hello world
            }
        },
        template: `
            <div @click="handleClick">{{message}}</div>
        `
    });
    const vm = app.mount('#root');
</script>
  • methods:方法可以和事件进行绑定,也可以在差值表达式{{}}中使用
<script type="text/javascript">
    const app = Vue.createApp({
        data() {
            return {
                message: "hello world",
            }
        },
        methods: {
            handleString(str) {
                return str.toUpperCase();
            }
        },
        template: `
            <div>{{handleString(message)}}</div>
        `
    });
    const vm = app.mount('#root');
</script>
  • computed:在computed中可以进行数据的计算。

进行计算的三种方式:

<script type="text/javascript">
    const app = Vue.createApp({
        data() {
            return {
                price: 5,
                count: 2
            }
        },
        computed: {
            total() {
                return this.price * this.count;
            }
        },
        methods: {
            getTotal() {
                return this.price * this.count;
            }
        },
        template: `
            <div>{{ parseInt(price) * parseInt(count) }}</div>
            <div>{{total}}</div>
            <div>{{getTotal()}}</div>
        `
    });
    const vm = app.mount('#root');
</script>

computed和methods中的计算有什么区别?

  • 只有当computed中所依赖的数据变化的时候,computed才会重新执行一次。而当页面重新渲染的时候,methods中的方法就会重新执行一次。

  • computed中采用了缓存的机制,所以使得性能更加高效。

  • watch:对一个数据进行监听,当这个数据发生变化的时候,就会被触发。

<script type="text/javascript">
    const app = Vue.createApp({
        data() {
            return {
                num : 10
            }
        },
        watch: {
			// 当num发生变化后,1秒后就会打印出修改过的新值和之前的旧值
            num(cur, prev) {
                setTimeout(() => {
                    console.log(cur, prev);
                }, 1000);
            }
        },
        template: "<div>{{num}}</div>"
    });
    const vm = app.mount('#root');
</script>

computed底层采用的就是watch,所以当计算数据结果来进行同步操作的话,使用封装过后的computed更简单。但是如果想要进行一些异步操作的话,就需要使用到watch。

总结:

  • computed和method都能实现的功能,建议使用computed,因为它有缓存性能更高
  • computed和watch都能实现的功能,建议使用computed,因为它更简洁

样式绑定语法

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="https://unpkg.com/vue@next"></script>
    <title>Hello Vue</title>
</head>
<style>
    .red {
        color: red;
    }
    .green {
        color: green;
    }
    .font {
        font-size: 30px;
    }
</style>
<body>
    <div id="root"></div>
</body>
<script type="text/javascript">
    const app = Vue.createApp({
        data() {
            return {
                // 使用字符串的方式选择class
                classString: "red",
                // 使用数组的形式选择class
                classArray: ["red", "font", {green: false}],
                // 使用键值对的方式选择class
                classObject: {
                    red: true,
                    font: true,
                    green: false
                },
                // 可以使用字符串的方式来定义style样式
                styleString:"color: blue; font-size: 30px",
                // 也可以写成键值对的形式,效果同上但是更方便查看
                styleObject: {
                    color: "orange",
                    fontSize: "30px",
                }
            }
        },
        template: `
            <div :class="classString">Hello World</div>
            <div :class="classArray">Hello World</div>
            <div :class="classObject">Hello World</div>

            <div :style="styleString">Hello World</div>
            <div :style="styleObject">Hello World</div>
            
            <demo :class="classObject" :style="styleObject"/>
        `
    });
    app.component("demo", {
        template:`
        <div :class="$attrs.class">demo1</div>
        <div :style="$attrs.style">demo2</div>
        `
    });
    const vm = app.mount('#root');
</script>
</html>

补充:

  1. 在标签中绑定属性值的话,采用键值对的方式更加数据驱动,从而扩展性更强一些。
  2. 如果子组件(被调用的一方组件叫做子组件)中的标签超过一个的时候,父组件的class和style属性就需要自己手动继承。如果只有一个的话,可以直接继承父组件的属性。

总结:

  • 如果想给一个组件加样式的话,可以使用class或者style。两者都可以在data中定义字符串,也可以定义字典。而class还可以使用数组。并且style定义的字典中写的是添加的样式,而class定义的字典是选择已经写好的class

条件渲染

v-if和v-show的区别以及v-else-if,v-else

v-if和v-show的条件为true的时候,两者都会将组件显示出来。但是当条件为false的时候,v-if会直接将dom标签移除掉。而v-show会设置dom标签的属性display:none从而隐藏标签而不是销毁标签。因此在需要频繁显示隐藏标签时,使用v-show可以避免频繁销毁重建dom标签,所以性能会更高一点。

v-if,v-else-if,v-else可以直接像普通的if,elseif,else一样使用,只不过标签之间需要紧挨着,否则会报错。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="https://unpkg.com/vue@next"></script>
    <title>Hello Vue</title>
</head>
<body>
    <div id="root"></div>
</body>
<script type="text/javascript">
    const app = Vue.createApp({
        data() {
            return {
                show: false,
                condtionOne: false,
                condtionTwo: true
            }
        },
        template: `
            <div v-if="show">Hello World</div>
            <div v-show="show">Hello World</div>

            <div v-if="condtionOne">if</div>
            <div v-else-if="condtionTwo">elseif</div>
            <div v-else>else</div>
        `
    });
    const vm = app.mount('#root');
</script>
</html>

列表循环渲染

v-for循环数组和对象

<script type="text/javascript">
    const app = Vue.createApp({
        data() {
            return {
                listArray: ['zhy', 'man', 18],
                listObject: {
                    name: "zhy",
                    gender: "man",
                    age: 18
                }
            }
        },
        template: `
        <div>
            <div v-for="(item, index) in listArray" :key="index">{{index}} -> {{item}}</div>
            <div v-for="(value, key, index) in listObject" :key="index">{{index}} -> {{key}} -> {{value}}</div>
        </div>
        `
    });
    const vm = app.mount('#root');
</script>

注意:页面中常常会存在一些当页面刷新过后依然不会改变的元素,所以vue为了提高性能会将这些元素不重新刷新,但是需要给这些元素添加上一个可以唯一标识的key。在标签中显式的内容需要使用{{}}来绑定数据,但是标签的属性值中可以直接使用数据。

配合v-for在列表中动态修改数组和对象内容

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="https://unpkg.com/vue@next"></script>
    <title>Hello Vue</title>
</head>
<body>
    <div id="root"></div>
</body>
<script type="text/javascript">
    const app = Vue.createApp({
        data() {
            return {
                listArray: ['zhy', 'male', 18],
                listObject: {
                    name: "zhy",
                    gender: "male",
                    age: 18
                }
            }
        },
        methods: {
            // 动态修改数组的方法
            // 1.通过函数来修改数组
            handleAddBtnClick() {
                this.listArray.push('hello');
            },
            handlePopBtnClick() {
                this.listArray.pop();
            },
            handleShiftBtnClick() {
                this.listArray.shift();
            },
            handleUnshiftBtnClick() {
                this.listArray.unshift('hello');
            },
            handleReverseBtnClick() {
                this.listArray.reverse();
            },
            // 2.直接替换数组
            handleReplace() {
                this.listArray = ['孔子', '孟子', '老子'];
            },
            // 3. 更新数组内容
            handleUpdate() {
                this.listArray[0] = '孔子';
            },
            // 在对象中条件元素
            handleAddObject() {
                this.listObject.school = 'nlg',
                this.listObject.hobby = 'programming'
            }
        },
        template: `
        <div>
            <div v-for="(item, index) in listArray" :key="index">{{index}} -> {{item}}</div>
            <button @click="handleAddBtnClick">尾插</button>
            <button @click="handlePopBtnClick">尾删</button>
            <button @click="handleShiftBtnClick">头删</button>
            <button @click="handleUnshiftBtnClick">头插</button>
            <button @click="handleReverseBtnClick">反转</button>
            <br/>
            <button @click="handleReplace">替换</button>
            <button @click="handleUpdate">更新</button>
            <br/>
            <div v-for="(value, key, index) in listObject" :key="index">{{index}} -> {{key}} -> {{value}}</div>
            <button @click="handleAddObject">添加</button>
        </div>
        `
    });
    const vm = app.mount('#root');
</script>
</html>

注意:

  • 如果想要在v-for中使用v-if进行判断的话,不能在同一个标签中同时进行循环和判断,因为循环的优先级比判断要高。所以v-if需要在当前标签中再嵌套一层标签。
  • 因为嵌套一层标签会使得我们不想要外层的标签,所以此时外层的标签可以使用template占位符记进行替换,template只是一个占位符,用于对标签进行操作,而不占是实际的标签。
<script type="text/javascript">
    const app = Vue.createApp({
        data() {
            return {
                listArray: ['zhy', 'male', 18],
            }
        },
        template: `
        <div>
            <div 
                v-for="(item, index) in listArray" 
                :key="index"
            >
                <div v-if="item !== 18">
                {{index}} -> {{item}}
                </div>
            </div>
        </div>
        <hr/>
        <div>
            <template 
                v-for="(item, index) in listArray" 
                :key="index"
            >
                <div v-if="item !== 18">
                {{index}} -> {{item}}
                </div>
            </template>
        </div>
        `
    });
    const vm = app.mount('#root');
</script>

![[Pasted image 20220430110102.png]]

事件绑定

事件绑定的基础语法

  • 一般在绑定一个函数的时候,只需要写函数名即可。但是如果想要同时绑定多个函数的话,就需要写上(),即function_name()这样的形式。
  • 每一个事件都有一个事件对象,如果没有函数没有参数的话,默认函数的第一个参数就是该事件对象。但是如果函数有参数,那么就需要在调用函数的地方传递一个参数$event才可以在函数使用该对象。
<script type="text/javascript">
    const app = Vue.createApp({
        methods: {
            handleBtnClick(str, event) {
                alert(str);
                console.log(event);
            },
            handleBtnClick1() {
                alert("hello world!!!");
            },
        },
        template: `
            <button @click="handleBtnClick('hello world', $event), handleBtnClick1()">点击</button>
        `
    });
    const vm = app.mount('#root');
</script>

事件绑定中的修饰符

事件在绑定后可以对事件进行修饰,即添加一些在执行事件是会执行的默认操作。

事件有两种修饰符:事件修饰符,按键修饰符,鼠标修饰符和精确修饰符

事件修饰符.stop .prevent .self .capture .once .passive等等

  • .stop:停止事件的冒泡传递
  • .capture:停止事件的向下传递
  • .self:只有自身可以触发事件
  • .once:事件只能触发一次
<script type="text/javascript">
    const app = Vue.createApp({
        methods: {
            handleBtnClick() {
                alert("button click");
            },
            handleDivClick() {
                alert("div click");
            },
        },
        template: `
            <div>
                <div @click.once="handleDivClick">
                    <span>Hello World!!!</span>
                    <button @click.stop="handleBtnClick">点击</button>
                </div>
            </div>
        `
    });
    const vm = app.mount('#root');
</script>

按键修饰符:

  • enter
  • tab
  • esc
  • delete
  • up
  • down
  • left
  • right

鼠标修饰符:

  • left:左键
  • right:右键
  • middle:滚轮

精确修饰符:必须当下点击指定按键或者鼠标才可以触发事件

  • exact:精确点击
<script type="text/javascript">
    const app = Vue.createApp({
        methods: {
            handleDivClick() {
                console.log("div click");
            },
            handleInput() {
                console.log("keydown");
            },
        },
        template: `
            <div>
                <div @click.right="handleDivClick">Hello World!!!</div>
                <div @click.ctrl.exact="handleDivClick">Hello World!!!</div>
                <input @keydown.delete="handleInput"/>
            </div>
        `
    });
    const vm = app.mount('#root');
</script>

表单中的双向绑定指令

双向绑定的意思就是将表单中的元素和data中的数据绑定,当表单中的元素进行变化的时候,data也相应变化,当data中的数据变化的时候,表单中的元素也相应变化。

<script type="text/javascript">
    const app = Vue.createApp({
        data() {
            return {
                message: 'hello world',
                listArray: [],
                checkStr: '',
            }
        },
        methods: {
        },
        template: `
            <div>
                <span>{{message}}</span>
                <input v-model="message"/>
                <textarea v-model="message"/>
            </div>
            <div>
                {{listArray}}
                hello <input type="checkbox" v-model="listArray" value="hello"/>
                world <input type="checkbox" v-model="listArray" value="world"/>
                !!! <input type="checkbox" v-model="listArray" value="!!!"/>
                <br/>
                {{checkStr}}
                男<input type="radio" v-model="checkStr" value="男"/>
                女<input type="radio" v-model="checkStr" value="女"/>
            </div>
        `
    });
    const vm = app.mount('#root');
</script>

注意:

  • checkbox和radio绑定的值只能为true或者false。绑定的值为数组的话,那么数组中就可以拿到勾选的条目的value值。

  • select中的双向绑定

<script type="text/javascript">
    const app = Vue.createApp({
        data() {
            return {
                listArray: [],
                options: [ {
                        text: 'A',
                        value: {value:'A'}
                    }, {
                        text: 'B',
                        value: {value:'B'}
                    }, {
                        text: 'C',
                        value: {value:'C'}
                    }],
            }
        },
        template: `
            <div>
                {{listArray}}
                <select v-model="listArray">
                    <option v-for="item in options" :value="item.value">{{item.text}}</option>
                </select>
            </div>
        `
    });
    const vm = app.mount('#root');
</script>

true-value
false-value
.lazy
.number:类型转化
.trim:去除前后空格

v-model的高级用法和修饰符

在v-model中可以使用true-valuefalse-value来定义值去确定当前是true/false

修饰符:

  • lazy:双向绑定的数据不会立即变化,只有当表单失去焦点才会变化
  • number:将绑定的数据类型转化为number
  • trim:去除掉绑定数据的前后的多余空格
<script type="text/javascript">
    const app = Vue.createApp({
        data() {
            return {
                value: "world",
                message: "",
                num: '',
            }
        },
        template: `
            <div>
                {{value}}
                <input type="checkbox" v-model="value" true-value="hello" false-value="world"/>
                <br/>
                {{message}}
                <input v-model.lazy="message"/>
                <input v-model.trim="message"/>
                <br/>
                {{typeof num}}
                <input v-model.number="num" type="number"/>
            </div>
        `
    });
    const vm = app.mount('#root');
</script>

组件的理念

组件的定义以及复用性,局部组件和全局组件

组件具有复用性,独立性、
app.component定义的全局组件

  1. 组件的意义就是让整个页面可以分模块独立去开发,并且每一个组件都可以复用。所以组件具有独立性和复用性
  2. 组件分为全局组件和局部组件,全局组件可以使用app.component挂载到app实例下。局部组件是直接通过定义变量的方式来定义。
    1. 全局组件就算不使用也会挂载到对应的app下,处处都可以使用,所以使用简单,单对性能消耗比较大。一般全局组件名字使用小写字符开头,以-作为分隔符
    2. 局部组件在不使用的时候,只是一个变量,不会消耗多余的性能。当局部组件在app的component中注册后才能使用。一般局部组件的名字是以大驼峰的方式命名。局部组件在注册的时候,要做一个名字和组件名之间的映射。如果不写映射的话,vue也会自动将大驼峰转换成小写字母和-的组合,所以组件的命名要规范,
<script type="text/javascript">   

    const HelloWorld = {
        template: `
            <div>Hello World!!!</div>
        `
    }
    const app = Vue.createApp({
        components: {
            HelloWorld,
            // 相当于'hello-world':HelloWorld
        },
        template: `
            <count-down />
            <hello-world />
        `
    });

    app.component('count-down',{
        data() {
            return {
                count: 60
            }
        },
        methods: {
            handleCount() {
                console.log('hello world');
                setInterval(() => {
                    this.count -= 1;
                }, 100);
            }
        },
        template:`
            <div @click="handleCount">{{count}}</div>
        `
    });

    const vm = app.mount('#root');
</script>

组件间传值及传值校验

光光定义组件使得组件具有了很强的独立性,但是往往子组件要和父组件进行数据的传递,只需要在组件中定义一个属性,并在组件内部通过props来接收即可。

传递数据分为两种:静态传参和动态传参。

  • 静态传参:直接将参数传递给组件,这样的方式往往只能传递一个字符串。
  • 动态传参:在父组件中的data()中定义参数,通过v-bind绑定组件的属性,这样就可以传递不同类型的参数了。
<script type="text/javascript">   
    const app = Vue.createApp({
        data() {
            return {
                num: 123,
            }
        },
        template: `
            <test content="123"/>
            <test :content="num"/>
        `
    });

    app.component('test', {
        props: ['content'],
        template:`<div>{{ content }}</div>`
    });

    const vm = app.mount('#root');
</script>

一般通过props来接收参数,如果只是接收参数的话,可以使用数组来接收。但是同时想要对传递的参数进行校验,那么就可以使用字典来接收,然后再字典内部进行校验。

不同类型的校验:

  • type:String,Boolean,Number,Array,Object,Function,Symbol
  • required:必填
  • default:默认值
  • validator:校验
<script type="text/javascript">   
    const app = Vue.createApp({
        data() {
            return {
                num: 123,
            }
        },
        template: `
            <test :content="num"/>
        `
    });

    app.component('test', {
        props: {
            content: {
                // 校验类型
                type: Number,
                // 是否一定要传递参数
                required: true,
                // 默认值
                // 也可以写成 default: 456,
				default: () => {
					return 456;
				},
                // 数据有效性校验
                validator: (num) => {
					// 返回一个boolean
                    return num < 1000;
                }
            }
        },
        template:`<div>{{ content }}</div>`
    });

    const vm = app.mount('#root');
</script>

单向数据流的理解

当父组件需要传递很多参数到子组件中的时候,可以不同v-bind:属性名="数值型"的方式动态绑定,可以直接将多个参数放在一个对象中,然后使用v-bind="对象"来绑定一个对象,子组件中会将字典中的键值对一个一个自动展开。

<script type="text/javascript">   
    const app = Vue.createApp({
        data() {
            return {
                a: 123,
                b: 456,
                c: 789,
                params: {
                    a: 123,
                    b: 456,
                    c: 789,
                }
            }
        },
        template: `
            <test :a="a" :b="b" :c="c"/>
            <test v-bind="params" />
        `
    });

    app.component('test', {
        props: ['a', 'b', 'c'],
        template:`<div>{{a}} {{b}} {{c}}</div>`
    });

    const vm = app.mount('#root');
</script>

注意:

  • 属性值有一个命名规范:传递的属性名需要以小写字母加-的方式,但是在子组件中接收的时候要用大驼峰的方式接收
  • 这个要和定义和接收局部组件名区分,局部组件名需要以大驼峰的形式,但是在component中接收组件的时候,要用小写加-的方式接收。
  • 总结:在根组件中,无论是接收组件,还是传递属性值命名都是小写加-的方式。在子组件中无论是接收属性值还是定义组件名都要以大驼峰命名。
<script type="text/javascript">   
    const app = Vue.createApp({
        data() {
            return {
                content: "hello world",
            }
        },
        template: `
            <test :content-hello="content"/>
        `
    });

    app.component('test', {
        props: ['contentHello'],
        template:`<div>{{contentHello}}</div>`
    });

    const vm = app.mount('#root');
</script>
  • 单向数据流:父组件可以给子组件传递数据,但是数据本身是只读的,不能修改。
    • 解释:父组件动态传递的数据可以同时给多个子组件使用。而每一次子组件应该是相互独立的,如果所有的子组件可以共用父组件传递的同一个数据的话,那么子组件会耦合起来了。因此父组件传递的数据是只读的,在子组件中不能修改它的值。
<script type="text/javascript">
    const app = Vue.createApp({
        data() {
            return {
                num: 1
            }
        },
        template: `
            <demo :num="num"/>
        `
    });

    app.component('demo', {
        props: ['num'],
        data() {
            return {
                myNum: this.num
            }
        },
        methods: {
            handleAddNum() {
                // this.num += 1; // 错误写法,子组件中不能使用父组件传递过来的数据
                this.myNum += 1;
            }
        },
        template:`<div @click="handleAddNum">{{myNum}}</div>`
    });

    const vm = app.mount('#root');
</script>

Non-Props属性

  • 如果当父组件传递给子组件参数,但是子组件并没有使用props接收的话,就会使用到Non-Props属性。
    • 如果子组件中只有一个标签的话,那么传递的参数会直接放在子组件的那一个标签中当做属性
    • 如果子组件中不止一个标签的话,那么传递的参数就不会同时作用于所有的组件。要是想用传递过来的参数的话,可以使用vue中自带的$attrs变量来进行赋值
      • 如果想要接收全部的参数,可以直接v-bind="$attrs"
      • 如果只想要接收部分参数,可以使用v-bind:属性名="$attrs.属性名"来接收。
      • 另外如果想要接收传递的参数可以将子组件的inheritAttrs设置为false即可。
<script type="text/javascript">

    const Test1 = {
        template:"<div>hello world</div>" 
    };

    const Test2 = {
        inheritAttrs: true,// 可以选择不接收任何属性
        template:`
            <div v-bind="$attrs">hello world</div>
            <div :attr1="$attrs.attr1">hello world</div>
            <div :attr2="$attrs.attr2" :attr3="$attrs.attr3">hello world</div>
        `
    };

    const app = Vue.createApp({
        components: {
            Test1,
            Test2,
        },
        data() {
            return {
                content: "hello world",
            }
        },
        template: `
            <test1 :content="content" style="color:red" />
            <test2 attr1="a" attr2="b" attr3="c" />
        `
    });

    const vm = app.mount('#root');
</script>

![[Pasted image 20220430192003.png]]

父子组件间如何通过事件通信

前面说过父组件传递给子组件的数据是只读的,不能在子组件中修改。但是子组件可以使用app中的emit属性来自定义事件去通知父组件修改父组件中的数据,这样父组件再传递给子组件数据的时候,子组件接收到的数据也就变化了。

  • 功能:每一次点击数字,都会触发子组件的handleAddNum函数,然后子组件中自定义一个事件addOne,父组件中可以通过@来接听这个事件(前面说明子组件中的命名格式是大驼峰,而根组件中要改成对应的小写字母加-的命名风格,所以子组件中的addOne事件到父组件中就成了add-one事件),最终父组件触发handleAddOne函数,让count加一。
<script type="text/javascript">

    const app = Vue.createApp({
        data() {
            return {
                num: 1
            }
        },
        methods: {
            handleAddOne() {
                this.num += 1;
            }
        },
        template: `
            <demo :num="num" @add-one="handleAddOne"/>
        `
    });

    app.component('demo', {
        props: ['num'],
        methods: {
            handleAddNum() {
                this.$emit('addOne');
            }
        },
        template:`<div @click="handleAddNum">{{num}}</div>`
    });

    const vm = app.mount('#root');
</script>

自定义事件也可以传递参数。子组件中传递的参数可以在父组件中监听这个事件的函数中使用,即子组件中给addOne传递的参数可以在父组件的handleAddOne中使用。

<script type="text/javascript">

    const app = Vue.createApp({
        data() {
            return {
                num: 1
            }
        },
        methods: {
			// 使用传递来的参数
            handleAddOne(param1, param2) {
                this.num += param1 + param2;
            }
        },
        template: `
            <demo :num="num" @add-one="handleAddOne"/>
        `
    });

    app.component('demo', {
        props: ['num'],
        methods: {
            handleAddNum() {
				// 传递参数
                this.$emit('addOne', 2, 4);
            }
        },
        template:`<div @click="handleAddNum">{{num}}</div>`
    });

    const vm = app.mount('#root');
</script>
  • 子组件中可以使用数组来定义emits属性中可以触发哪些事件。也可以在emits中定义字典来检验自定义事件传递的参数的合法性
<script type="text/javascript">

    const app = Vue.createApp({
        data() {
            return {
                num: 1
            }
        },
        methods: {
            handleAddOne(num) {
                this.num = num;
            }
        },
        template: `
            <demo :num="num" @add-one="handleAddOne"/>
        `
    });

    app.component('demo', {
        props: ['num'],
        // emits: ['addOne'],
        emits: {
            // 对addOne事件进行数据校验
            addOne: (val) => {
                if (val > 10) {
                    return false;
                }
                return true;
            }
        },
        methods: {
            handleAddNum() {
                this.$emit('addOne', this.num + 5);
            }
        },
        template:`<div @click="handleAddNum">{{num}}</div>`
    });

    const vm = app.mount('#root');
</script>

上面这个功能其实就是父组件给子组件传递参数,然后子组件再返回一个数据给子组件,这个功能其实就类似于数据的双向绑定,其实v-model在这里也是可以适用的。

v-model的高级用法

  1. 如果使用v-model进行数据双向绑定的话,其实写法很固定,父组件中将需要绑定的数据使用v-mode传递过来,然后子组件中props中一定要用modelValue这个名字来接收传递的数据,然后在子组件的this.$emit中触发的事件的名字一定是update:modelValue,然后将修改过的数据传递给父组件,传递的数据会自动覆盖父组件中的数据,这样就形成了数据的双向绑定。
<script type="text/javascript">

    const app = Vue.createApp({
        data() {
            return {
                num: 1
            }
        },
        methods: {
            handleAddOne(num) {
                this.num = num;
            }
        },
        template: `
            <demo v-model="num" />
        `
    });

    app.component('demo', {
        props: ['modelValue'],
        methods: {
            handleAddNum() {
                this.$emit('update:modelValue', this.modelValue + 1);
            }
        },
        template:`
            <div @click="handleAddNum">{{modelValue}}</div>
        `
    });

    const vm = app.mount('#root');
</script>

如果想要给双向绑定的数据起一个名字的话,可以以v-model:数据名="传递的数据"的方式。

<script type="text/javascript">

    const app = Vue.createApp({
        data() {
            return {
                num1: 1,
                num2: 1
            }
        },
        template: `
            <demo v-model:num1="num1" v-model:num2="num2"/>
        `
    });

    app.component('demo', {
        // 接收两个双向绑定的数据
        props: ['num1', 'num2'],
        methods: {
            handleAddNum1() {
                // 更新num1
                this.$emit('update:num1', this.num1 + 1);
            },
            handleAddNum2() {
                // 更新num2
                this.$emit('update:num2', this.num2 + 1);
            }
        },
        template:`
            <div @click="handleAddNum1">{{num1}}</div>
            <div @click="handleAddNum2">{{num2}}</div>
        `
    });

    const vm = app.mount('#root');
</script>
  1. v-mode除了可以通过其别名的方式传递双向绑定的数据,也可以给传递的数据添加上自定义的修饰符。

组件中使用modelModifiers来查看修饰符是否存在。

<script type="text/javascript">

    const app = Vue.createApp({
        data() {
            return {
                message: 'a'
            }
        },
        template: `
            <demo v-model.uppercase="message"/>
        `
    });

    app.component('demo', {
        props: {
            'modelValue': String,
            'modelModifiers': {
                // 默认返回一个空对象
                default: () => {
                    return {}
                }
            }
        },
        methods: {
            handleClick() {
                let newVal = this.modelValue + 'a';
                // 当双向绑定的事件有uppercase这个修饰符的时候,this.modelModifiers.uppercase=true
                if (this.modelModifiers.uppercase) {
                    newVal = newVal.toUpperCase();
                }
                this.$emit('update:modelValue', newVal);
            }
        },
        template:`
            <div @click="handleClick">{{modelValue}}</div>
        `
    });

    const vm = app.mount('#root');
</script>

使用插槽和具名插槽解决组件内容传递问题

当父组件想要传递一个标签给子组件的时候,通过传递属性值的方式进行传递的话,太过麻烦。此时就可以使用slot插槽,slot插槽可以定制化组件中的内容,slot中可以传递很多东西,可以是字符串,标签,另一个子组件等等。如果slot中没有传递数据的话,可以在slot标签中添加默认值。

但是slot标签在子组件中是无法绑定事件的,一般都是通过在slot标签外面加上一个span标签,然后对span标签进行绑定事件来解决的。

slot中使用的数据的作用域

  • 如果slot中传递的标签有一个{{}}包裹的变量,这个变量使用的是父组件中的变量替换,而不是子组件的变量
  • 总结:父模板中调用的数据使用的都是父模板中的数据。子模板中调用的数据都是子模板中的数据。
<script type="text/javascript">

    const app = Vue.createApp({
        data() {
            return {
                message: "提交"
            }
        },
        template: `
            <myform>
                Hello Slot~
                <button>{{message}}</button>
            </myform>
            <br/>
            <myform>
                Hello Slot!
                <span>{{message}}</span>
            </myform>
			<br/>
			<myform></myform>
        `
    });

    app.component('myform', {
        methods: {
            handleClick() {
                alert("hello");
            }
        },
        template: `
            <span @click="handleClick">
                <slot>default value</slot>
            </span>
        `
    });

    const vm = app.mount('#root');
</script>

具名插槽

如果想要将父组件中传递的slot拆分成多个部分使用的话,就不能像直接在子组件中直接使用slot标签了,而是要对父组件中的slot进行v-slot指令,并在子组件中指定slot的名字。

注意:

  • 在父组件中传递的slot中使用v-slot指令,不能直接在标签上使用,而是要在标签的外面套一层占位符template,在template上使用v-slot执行。
  • 在template中使用v-slot传递数据的名字,可以简写成#数据名
<script type="text/javascript">

    const app = Vue.createApp({
        template: `
            <layout>
                <template #header>
                    <div>header</div>
                </template>
                <template v-slot:fonter>
                    <div>fonter</div>
                </template>
            </layout>
        `
    });

    app.component('layout', {
        template: `
            <div>
                <slot name="header"></slot>
                <div> content </div>
                <slot name="fonter"></slot>
            </div>
        `
    });

    const vm = app.mount('#root');
</script>

作用域插槽

子组件中使用slot只能决定slot的展示方式(展示的位置,循环展示等等),但是不能决定子组件展示的内容。当slot要展示的内容在子组件中,但此时又想要将这些数据展示在父组件中是就需要使用作用域插槽。即子组件将数据传递给父组件,然后父组件可以通过v-slot获得所有子组件传递的数据,从而可以在父组件中使用子组件中要展示的内容。

<script type="text/javascript">

    const app = Vue.createApp({
        template: `
            <layout v-slot="slotProps">
                <div>{{slotProps.item}}</div>
            </layout>
            <layout v-slot={item}>
                <span>{{item}}</span>
            </layout>
        `
    });

    app.component('layout', {
        data() {
            return {
                list: [1, 2, 3]
            }
        },
        template: `
            <div>
                <slot v-for="item in list" :item="item"/>
            </div>
        `
    });

    const vm = app.mount('#root');
</script>

注意:

  • 因为父组件通过v-slot需要接收全部的数据,所以可以使用{}解构的方法,将数据直接获得。这样就不用通过.的方式一个一个获取了。

动态组件和异步组件

动态组件:使用component标签中的is属性,可以根据数据的变化,进行动态切换组件。

动态组件其实就是为了简化使用v-show指令来判断不同组件的写法的。

<script type="text/javascript">

    const app = Vue.createApp({
        data() {
            return {
                curItem: 'input-item',
            }
        },
        methods: {
            handleClick() {
                if (this.curItem === 'input-item') {
                    this.curItem = 'div-item';
                } else {
                    this.curItem = 'input-item';
                }
            }
        },
        template: `
            <component :is="curItem"/>
            <br/>
            <input-item v-show="curItem === 'input-item'"/>
            <div-item v-show="curItem === 'div-item'"/>
            <button @click="handleClick">切换</button>
        `
    });

    app.component('input-item', {
        template: `
            <input />
        `
    });

    app.component('div-item', {
        template: `
            <div>Hello World</div>
        `
    })

    const vm = app.mount('#root');
</script>

异步的概念

  • 异步就是当前任务不是立即执行,而是在等待一段时间后才可以执行任务。所以异步就是不同步。
<script>
    console.log('a');
    console.log('b');
    setTimeout(() => {
        console.log('异步执行');
    }, 1000);
    console.log('c');
    console.log('d');
</script>

promise实现异步,当promise状态发生改变,就会触发then()中的响应函数。

状态改变有两种:

  1. pending=>fulfilled
  2. pending=>rejected

Promise对象中必须要传递一个参数,并且参数一定要是一个函数

promise有两个参数,如果是成功执行函数就使用resolve来执行函数,如果是执行函数就使用reject来执行函数,并且调用的地方需要使用try,catch来捕捉异常,否则会报错。

async/wait也是用于处理异步的,背后的原理也是promise

<script>
    // async表示异步函数,等价于f2()函数的写法
	async function f1() {
        return "hello async";
    }

    function f2() {
        return new Promise((resolve) => {
            resolve("hello async"); 
        });
    }
    
    async function f3() {
        // 因为await,所以函数会阻塞在await这儿
        let res = await f1();
        console.log(res);
        console.log('hello await');
    }
    f3()
</script>

异步组件就是异步执行某些组件的逻辑。

<script type="text/javascript">

    const app = Vue.createApp({
        template: `
            <async-item/>
        `
    });

    app.component('async-item', Vue.defineAsyncComponent(() => {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve({
                    template: `<div>Hello async component</div>`
                });
            }, 2000);
        })
    }));

    const vm = app.mount('#root');
</script>

注意:

  • 所有异步操作中都需要传入一个函数作为参数,例如defineAsyncComponent,Promise,setTimeout中,最后通过resolve返回一个组件,可以在组件的template中定义组件需要渲染的标签。

补充内容

  • v-once:让组件只渲染一次,即使组件中的数据发生了变化,组件也只渲染一次
<script type="text/javascript">

    const app = Vue.createApp({
        data() {
            return {
                count: 1
            }
        },
        template: `
            <div @click="count += 1" v-once>{{count}}</div>
        `
    });

    const vm = app.mount('#root');
</script>

即使触发事件后,count增加了,但是页面只会显示1。

  • ref:可以获得dom节点或者组件的引用,相当于拿到dom节点或者组件本身
<script type="text/javascript">

    const app = Vue.createApp({
        data() {
            return {
                count: 1
            }
        },
        mounted() {
            // 获得div标签
            console.log(this.$refs.count);
            // 获得子组件的引用,并使用子组件中的函数
            this.$refs.item.sayHello();
        },
        template: `
            <div ref="count">{{count}}</div>
            <item ref="item"/>
        `
    });

    app.component('item', {
        methods: {
            sayHello() {
                alert('Hello~');
            }
        },
        template: `<div></div>`
    });

    const vm = app.mount('#root');
</script>
  • provide/inject:父组件通过provide可以将数据跨组件传递,需要接收数据的组件使用inject属性接收
<script type="text/javascript">

    const app = Vue.createApp({
        data() {
            return {
                count: 1
            }
        },
        provide: {
            count: 1
        },
        template: `
            <child/>
        `
    });

    app.component('child', {
        template: `
            <child-child />
        `
    });

    app.component('child-child', {
        inject: ['count'],
        template: `
            <div>{{count}}</div>
        `
    });

    const vm = app.mount('#root');
</script>

在父组件中使用provide属性即可传递参数,但是如果使用对象来传递,那么传递的参数是一次性分配的,和父组件中的参数无关。所以要将provide写成一个函数,这样就可以将父组件的参数传递给其他组件了。

const app = Vue.createApp({
    data() {
        return {
            count: 1
        }
    },
    provide() {
        return {
            count: this.count
        }
    },
    template: `
        <child/>
        `
});

但是注意即使将父组件的参数传递过去了,但是这个数据不是和父组件绑定的。所以在组件中使用不会影响到父组件中的参数。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hyzhang_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值