Vue入门
  • 引入 Vue 的 cdn
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  • Vue入门程序 - 插值表达式
<div id="app">
    {{message}}
</div>
<script>
	var vm = new Vue({
    	el: "#app",
        data:{
            message: "hello,vue!"
        }
    });
</script>

Vue的基础指令
  • v-text 和 v-html
<div id="app">
	<!-- v-text 会覆盖元素中原本的内容,未完全加载时会显示‘哈哈’-->
	<h4 v-text="msg">哈哈</h4>
	<!-- v-html 会将内容转义成html页面-->
    <p v-html="msg2"></p>
</div>
<script>
	var vm = new Vue({
		el: '#app',
		data: {
			msg: '123',
			msg2: '<h1>H1大标题</h1>',
		}
</script>
  • v-bind 属性绑定
<div id="app">
    <span v-bind:title="message">鼠标悬停此处查看动态绑定的提示信息</span>
</div>
<script>
    var vm = new Vue({
        el: "#app",
        data:{
            message: "hello,vue!"
        }
    });
</script>
  • v-show 控制显示
<div id="app">
    <h1 v-show="ok">Yes</h1>
</div>
<script>
    var vm = new Vue({
        el: "#app",
        data:{
            ok: false
        }
    });
</script>
  • v-if 和 v-else 控制显示
<div id="app">
    <h1 v-if="ok">Yes</h1>
    <h1 v-else>NO</h1>
</div>
<script>
    var vm = new Vue({
        el: "#app",
        data:{
            ok: false
        }
    });
</script>
  • v-if 、v-else-if 和 v-else 结构
<div id="app">
    <h1 v-if="type==='A'">a</h1>
    <h1 v-else-if="type==='B'">b</h1>
    <h1 v-else-if="type==='C'">c</h1>
    <h1 v-else>d</h1>
</div>
<script>
    var vm = new Vue({
        el: "#app",
        data:{
            type: 'B'
        }
    });
</script>
  • v-if 与 v-show 有啥区别
v-if 与 v-show 有啥区别
答案:
1. 实现原理不一样
v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
v-show 不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
即通过设置元素的 display:none,达到显示隐藏的作用。

2. 开销不一样
如果频繁的切换元素的状态,v-if 的开销会比较大,因为它涉及到条件块内各组件的重建和销
毁,(造成回流)而 v-show 只是切换元素的 css,v-show 的开销比较小。

3. 适用场景不一样
如果频繁的切换元素的状态,v-if 的开销会比较大,,v-show 的开销比较小。因此,v-show 更适合频繁切换的场景。
当然,v-show 只是设置了元素的 display 为 none,元素 dom 结构还是在那里的。
如果你不想让其他人看到这些 dom,需要使用 v-if。
  • v-for 遍历数组
<div id="app">
    <li v-for="(item, index) in items">
        num: {{item.id}} message: {{item.message}} index: {{index}}
    </li>
</div>
<script>
    var vm = new Vue({
        el: "#app",
        data: {
            items: [
                {id: 1, message: 'BLU1'},
                {id: 2, message: 'BLU2'},
                {id: 3, message: 'BLU3'}
            ]
        }
    });
</script>

在这里插入图片描述

  • v-on 绑定事件
<div id="app">
    <button v-on:click="sayHi">Click Me</button>
</div>
<script>
    var vm = new Vue({
        el: "#app",
        data: {
            message: "Hello, BLU!"
        },
        methods: {
            sayHi: function () {
                alert(this.message);
            }
        }
    });
</script>

在这里插入图片描述

  • v-model 数据双向绑定
<div id="app">
    输入的文本:<input type="text" v-model="message"><br>
    {{message}}
</div>
<script>
    var vm = new Vue({
        el: "#app",
        data: {
            message: ""
        }
    });
</script>

在这里插入图片描述

  • v-once 只渲染元素和组件一次,后续改变将不会在DOM上渲染
<body>
    <div id="vm" v-once>
        {{key}}
    </div>
</body>
<script>
	var vm = new Vue({
		el: '#vm',
    	data: {
    		key: 'Hello, Vue'
    	}
 	})
</script>

自定义指令
  • 自定义指令(不带参数)
<div id="app">
	<input type="text" >
	<input type="text" v-blu>
</div>
<script>
	//参数1指定指令的名称,参数2指定指令的业务逻辑
	Vue.directive('blu', {
		// 参数el表示指令所绑定的元素
		inserted: function(el) {
			el.focus();
		}
	});

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

此时,加了自定义指令 v-blu 的输入框在页面一加载时就处于选中(focus)状态

  • 自定义指令(带参数)
<div id="app">
	<input type="text" v-color='msg'>
</div>
<script>
    Vue.directive('color', {
    	// 参数 binding 对象中的 value 属性指定了指令的绑定值
        bind: function(el, binding) {
            console.log(binding);
            el.style.backgroundColor = binding.value;
        }
    });

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

在这里插入图片描述
指令定义对象的钩子函数:

bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。

inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。

  • 自定义局部指令
<div id="app">
	<input type="text" v-color='msg'>
</div>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            msg: 'blue'
        },
        directives: {
            color: {
                bind: function(el, binding) {
                    el.style.backgroundColor = binding.value;
                }
            }
        }
    })
</script>

在这里插入图片描述


Vue 计算属性 computed

将计算出来的结果放入缓存,以节约系统的开销

  • 用法示例
<div id="app">
	<!-- 调用方法 -->
    <p>{{currentTime1()}}</p>
    <!-- 调用计算属性 -->
    <p>{{currentTime2}}</p>
</div>
<script>

    var vm = new Vue({
        el: "#app",
        data: {
            message: "Hello, BLU!"
        },
        methods: {
            currentTime1: function () {
                return Date.now();
            }
        },
        computed: {
            currentTime2: function () {
                return Date.now();
            }
        }
    });

</script>

在这里插入图片描述
在这里插入图片描述

  • computed (计算属性) 和 methods 的区别?
当依赖的属性发生改变时,计算属性与方法都会被重新调用,此时二者没有区别。
当依赖的属性再次调用时,计算属性会自动获取数据的缓存,而不是重新调用计算属性计算过程。
而无论依赖的属性方法是否发生变化,只要再次调用方法,就会重新执行方法的内容。
所以计算属性的效率更高

Vue 侦听器 watch

响应数据的变化

  • 用法示例
<div id="app">
    <input type="text" v-model="firstName">
    <input type="text" v-model="lastName">
    <p>{{fullName}}</p>
</div>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            firstName: 'Yin',
            lastName: 'Yang',
            fullName: 'Yin Yang'
        },
        watch: {
            firstName: function(val) {
                this.fullName = val + ' ' + this.lastName;
            },
            lastName: function(val) {
                this.fullName = this.firstName + ' ' + val;
            }
        }
    })
</script>

在这里插入图片描述

  • 侦听器应用场景:判断用户名是否可用
<div id="app">
    用户名:<input type="text" v-model.lazy="userName">
    <span>{{tip}}</span>
</div>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            userName: '',
            tip: ''
        },
        watch: {
            userName: function(val) {
                this.tip = '正在验证...';
                this.checkName(val);
            }
        },
        methods: {
            checkName: function(uname) {
                var that = this;
                setTimeout(function() {
                    //模拟接口调用
                    if (uname == 'admin') {
                        that.tip = "用户名已经存在";
                    } else {
                        that.tip = "用户名可用";
                    }
                }, 2000);
            }
        }
    })
</script>

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


Vue 过滤器 filter
  • 一次过滤

直接将首字母变成大写

<div id="app">
    <input type="text" v-model="msg">
    <div>{{msg | upper}}</div>
</div>
<script>
    Vue.filter('upper', function(val) {
        return val.charAt(0).toUpperCase() + val.slice(1);
    })
    var vm = new Vue({
        el: '#app',
        data: {
            msg: ''
        }
    })
</script>

在这里插入图片描述
在这里插入图片描述

  • 多次过滤

先将全部字母变成小写,再将首字母变成大写

<div id="app">
    <input type="text" v-model="msg">
    <div>{{msg | lower | upper}}</div>
</div>
<script>
    Vue.filter('upper', function(val) {
        return val.charAt(0).toUpperCase() + val.slice(1);
    });
    Vue.filter('lower', function(val) {
        return val.toLowerCase();
    })
    var vm = new Vue({
        el: '#app',
        data: {
            msg: ''
        }
    })
</script>

在这里插入图片描述

  • 过滤器携带参数
<div id="app">
    <div>{{date | format('yyyy-MM-dd')}}</div>
</div>
<script>
    Vue.filter('format', function(val, arg) {
        if (arg == 'yyyy-MM-dd') {
            var ret = '';
            ret += val.getFullYear() + '-' + (val.getMonth() + 1) + '-' + val.getDate();
            return ret
        }
    });

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

在这里插入图片描述


  • Axios 异步通信

1. 引入 Axios 的 cdn

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

2. 准备 json 文件

{
  "name": "BLU",
  "url": "http://www.baidu.com",
  "page": 1,
  "address": {
    "country": "China",
    "city": "南京",
    "street": "安德门大街"
  }
}

Vue 生命周期

主要阶段:

  • 挂载

beforecreated:el 和 data 并未初始化
created:完成了 data 数据的初始化,el没有
beforeMount:完成了 el 和 data 初始化
mounted:完成挂载

  • 更新

beforeUpdate:数据更新之前
updated:数据更新之后

  • 销毁

beforeDestroy:实例销毁之前
destroyed:实例销毁之后

<body>
    <div id="vm">
        {{key}}
    </div>
</body>
<script>
    var vm = new Vue({
        el: '#vm',
        data: {
            key: 'Hello, Vue'
        },
        beforeCreate: function() {
            console.log("beforeCreate");
            console.log("key:" + this.key);
        },
        created: function() {
            console.log("created");
            console.log("key:" + this.key);
        },
        beforeMount: function() {
            console.log("beforeMount");
            console.log("key:" + this.key);
        },
        mounted: function() {
            console.log("mounted");
            console.log("key:" + this.key);
        },
        beforeUpdate: function() {
            console.log("beforeUpdate");
            console.log("key:" + this.key);
        },
        updated: function() {
            console.log("updated");
            console.log("key:" + this.key);
        },
        beforeDestroy: function() {
            console.log("beforeDestroy");
            console.log("key:" + this.key);
        },
        destroyed: function() {
            console.log("destroyed");
            console.log("key:" + this.key);
        }
    });
</script>

在这里插入图片描述


Vue 组件化开发
  • 全局组件注册
<div id="app">
    <button-counter></button-counter>
</div>
<script>
    Vue.component('button-counter', {
    	// 组件模板必须只包含一个根元素
    	template: '<button @click="handle()">点击了{{count}}次</button>',
        // 组件的 data 必须是一个函数
        data: function() {
            return {
                count: 0
            }
        },
        methods: {
			handle: function() {
				this.count++;
			}
		}
    })

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

在这里插入图片描述

  • 局部组件注册
<div id="app">
    <hello-world></hello-world>
    <hello-blu></hello-blu>
</div>
<script>
        // 局部组件只能在定义它的父组件中使用
        var HelloBLU = {
            data: function() {
                return {
                    msg: 'Hello,BLU!'
                }
            },
            template: '<div>{{msg}}</div>'
        };
        var HelloWorld = {
            data: function() {
                return {
                    msg: 'Hello,World!'
                }
            },
            template: '<div>{{msg}}</div>'
        };

        var vm = new Vue({
            el: '#app',
            components: {
                'hello-world': HelloWorld,
                'hello-blu': HelloBLU
            }
        })
</script>
  • 父组件通过 props 向子组件传值

注意点1:
如果在子组件 props 中接收的参数命名为驼峰形式(例如:menuTitle
则父组件给子组件传递的参数写法必须为短横杠形式(例如::menu-title=“xxx”
但如果使用的是字符串模板的形式,则该不存在该限制

注意点2:
如果父组件传递的是 num=‘12’,则子组件接收到的是字符串形式的‘12’
如果父组件传递的是 :num=‘12’,则子组件接收到的是数值类型的12
如果父组件传递的是 pboo=‘true’,则子组件接收到的是字符串形式的‘true’
如果父组件传递的是 :pboo=‘true’,则子组件接收到的是布尔类型的true

<div id="app">
    <blu title="来自父组件的值"></blu>
    <blu :title="ptitle" :content="pcontent"></blu>
</div>
<script>
    Vue.component('blu', {
        template: '<div>{{msg + "----" + title + "----" + content}}</div>',
        props: ['title', "content"],
        data: function() {
            return {
                msg: '子组件本身的数据'
            }
        }
    })

    var vm = new Vue({
        el: '#app',
        data: {
            ptitle: '动态绑定的标题',
            pcontent: '动态绑定的内容'
        }
    })
</script>

在这里插入图片描述

  • 子组件通过发起自定义事件 $emit 向父组件传值

注:通过 props 传递的值是单向的,虽然可以,但千万不要通过修改 props 传过来的值来直接修改父组件的值

Vue 可能会报如下警告:

[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value.
[Vue警告]:避免直接更改prop,因为每当父组件重新渲染时,该值都会被覆盖。 而是使用基于属性值的数据或计算属性。
<div id="app">
	<!-- 父组件监听子组件发起的自定义事件并调用对应的方法,$event代表子组件传过来的参数值 -->
	<blu :parr='parr' :pnum='pnum' @add-lemon="addlemon" @add-num="add($event)"></blu>
</div>
<script>
    Vue.component('blu', {
        template: `
			<div>
				<ul>
					<li :key='index' v-for='(item,index) in parr'>{{item}}</li>
    			</ul>
				<div>{{pnum}}</div>
				<div><button @click='parr.push("lemon")'>不要通过这种方式修改父组件中的值</button></div>
				<div><button @click='pnum++'>不要通过这种方式修改父组件中的值</button></div>
				<div><button @click='$emit("add-lemon")'>子组件发起add-lemon事件</button></div>
				<div><button @click='$emit("add-num",1000)'>子组件发起add-num事件,并传递一个参数1000</button></div>
			</div>
		`,
        props: ['parr', 'pnum']
    })

    var vm = new Vue({
        el: '#app',
        data: {
            pnum: 10,
            parr: ["orange", "apple", "bunana"]
        },
        methods: {
            addlemon: function() {
                this.parr.push("lemon");
            },
            add: function(val) {
                this.pnum = val;
            }
        }
    })
</script>

在这里插入图片描述

  • 兄弟组件之间通过事件中心传值
<div id="app">
    <div>父组件<button @click="handle">销毁事件</button></div>
    <blu-a></blu-a>
    <blu-b></blu-b>
</div>
<script>
	//定义全局事件中心
    var hub = new Vue();

    Vue.component('blu-a', {
        template: `
			<div>
				<div>A:{{num}}</div>
				<div>
					<button @click="handle()">点击</button>
    			</div>
    		</div>
		`,
        data: function() {
            return {
                num: 0
            }
        },
        methods: {
            handle: function() {
                hub.$emit('b-event', 1)
            }
        },
        mounted: function() {
            //监听事件
            hub.$on('a-event', (val) => {
                this.num += val;
            })
        }
    }),

	Vue.component('blu-b', {
        template: `
			<div>
				<div>B:{{num}}</div>
				<div>
					<button @click="handle()">点击</button>
    			</div>
    		</div>
		`,
        data: function() {
            return {
                num: 0
            }
        },
        methods: {
            handle: function() {
                hub.$emit('a-event', 10)
            }
        },
        mounted: function() {
            //监听事件
            hub.$on('b-event', (val) => {
                this.num += val;
            })
        }
    })

    var vm = new Vue({
        el: '#app',
        data: {},
        methods: {
            handle: function() {
                hub.$off('a-event');
                hub.$off('b-event');
            }
        }
    })
</script>

点击组件A的按钮,组件B的数字加1,点击组件B的按钮,组件A的数字加10,点击父组件的按钮,两个子组件按钮失效:
在这里插入图片描述

  • 组件插槽 slot
组件插槽基本用法:
<div id="app">
    <blu>404</blu>
    <blu>有一个错误信息</blu>
    <blu></blu>
</div>
<script>
    Vue.component('blu', {
        template: `
			<div>
				<strong>ERROR:</strong><slot>默认内容</slot>
    		</div>
		`
    })

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

在这里插入图片描述

具名插槽用法:

指定了 slot 的标签会插入到指定的插槽位置,没有指定的会插入到默认插槽

<div id="app">
    <blu>
        <p slot="header">标题内容</p>
        <p>主要内容1</p>
        <p>主要内容2</p>
        <p slot="footer">底部内容</p>
    </blu>
</div>
<script>
    Vue.component('blu', {
        template: `
			<div>
				<slot name='header'></slot>
				<slot></slot>
				<slot name='footer'></slot>
    		</div>
		`
    })

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

在这里插入图片描述

父组件通过作用域插槽获取子组件的值:
<div id="app">
    <blu :list='list'>
        <!-- 父组件通过slotProps接收子组件传来的值 -->
        <template slot-scope='slotProps'>
            <strong v-if='slotProps.info.id==2' class="current">{{slotProps.info.name}}</strong>
            <span v-else>{{slotProps.info.name}}</span>
        </template>
    </blu>
</div>
<script>
    Vue.component('blu', {
        // 子组件将数据绑定至info
        template: `
			<div>
				<li :key='item.id' v-for='item in list'>
					<slot :info="item"></slot>
    			</li>
    		</div>
		`,
        props: ['list']
    })

    var vm = new Vue({
        el: '#app',
        data: {
            list: [{
                id: 1,
                name: 'apple'
            }, {
                id: 2,
                name: 'banana'
            }, {
                id: 3,
                name: 'orange'
            }]
        }
    })
</script>
<style type="text/css">
    .current {
        color: red;
    }
</style>

在这里插入图片描述


Axios 异步通信
  • 1. 引入 Axios 的 js
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
  • 2. 准备 json 文件
{
  "name": "BLU",
  "url": "http://www.baidu.com",
  "page": 1,
  "address": {
    "country": "China",
    "city": "南京",
    "street": "安德门大街"
  }
}
  • 3. Axios 异步请求获取数据
<div id="app" v-clock>
    <div>{{info.name}}</div>
    <div>{{info.address.country}}</div>
    <div>{{info.address.city}}</div>
    <div>{{info.address.street}}</div>
    <a v-bind:href="info.url">链接</a>
</div>
<script>
    var vm = new Vue({
        el: "#app",
        data() {
            return {
                info: {
                    name: null,
                    address: {
                        country: null,
                        city: null,
                        street: null
                    },
                    url: null
                }
            }
        },
        mounted(){
            axios.get('data.json').then(response=>(this.info=response.data));
        }
    });
</script>

利用 v-clock 解决闪烁问题

<style>
	[v-clock]{
		display: none;
	}
</style>
  • 4. 结果
    在这里插入图片描述

Vue Router 路由
  • 使用示例
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
    <div>
        <router-link to="/a">link A</router-link>
        <router-link to="/b">link B</router-link>
    </div>
    <div>
        <!-- 路由占位符 -->
        <router-view></router-view>
    </div>
</div>
<script>
    var Acomponent = {
        template: '<h1>A component content</h1>'
    }
    var Bcomponent = {
        template: '<h1>B component content</h1>'
    }
    //创建路由实例对象
    var router = new VueRouter({
        routes: [{
            path: '/',
            redirect: '/a'
        }, {
            path: '/a',
            component: Acomponent
        }, {
            path: '/b',
            component: Bcomponent
        }]
    })
    var vm = new Vue({
        el: '#app',
        data: {},
        //挂载路由实例对象
        router: router
    })
</script>

在这里插入图片描述

  • 嵌套路由
<div id="app">
    <div>
        <router-link to="/a">link A</router-link>
        <router-link to="/b">link B</router-link>
    </div>
    <div>
        <router-view></router-view>
    </div>
</div>
<script>
    var Acomponent = {
        template: '<h1>A 组件内容</h1>'
    }
    var Bcomponent = {
        template: `
				<div>
					<h1>B 组件</h1>
					<div>
						<router-link to="/ba">链接1</router-link>
						<router-link to="/bb">链接2</router-link>
    				</div>
					<router-view/>
    			</div>`,
    }

    var BAComponent = {
        template: '<div>B中的a组件</div>'
    }
    var BBComponent = {
        template: '<div>B中的b组件</div>'
    }

    var router = new VueRouter({
        routes: [{
            path: '/',
            redirect: '/a'
        }, {
            path: '/a',
            component: Acomponent
        }, {
            path: '/b',
            component: Bcomponent,
            children: [{
                path: '/ba',
                component: BAComponent
            }, {
                path: '/bb',
                component: BBComponent
            }]
        }]
    })
    var vm = new Vue({
        el: '#app',
        data: {},
        router: router
    })
</script>

在这里插入图片描述

  • 动态路由匹配
<div id="app">
    <div>
        <router-link to="/user/1">User1</router-link>
        <router-link to="/user/2">User2</router-link>
        <router-link to="/user/3">User3</router-link>
    </div>
    <div>
        <router-view></router-view>
    </div>
</div>
<script>
    var User = {
        template: '<div><p> User的id是:{{$route.params.id}} </p></div>'
    }

    var router = new VueRouter({
        routes: [{
            path: '/user/:id',
            component: User
        }]
    })
    
    var vm = new Vue({
        el: '#app',
        data: {},
        router: router
    })
</script>

在这里插入图片描述
注:使用 $route 进行路由组件传参耦合性高,不灵活,你还可以使用以下方式传参:

<script>
    var User = {
        props: ['id', 'uname', 'age'],
        template: '<div><p> User的id是:{{id}} 用户名是:{{uname}} 年龄是: {{age}}</p></div>'
    }

    var router = new VueRouter({
        routes: [{
            path: '/user/:id',
            component: User,
            props: route => ({
                uname: 'zhangsan',
                age: '20',
                id: route.params.id
            })
        }]
    })
    
    var vm = new Vue({
        el: '#app',
        data: {},
        router: router
    })
</script>

在这里插入图片描述

  • 编程式导航
<div id="app">
    <div>
        <router-link to="/user">User</router-link>
    </div>
    <div>
        <router-view></router-view>
    </div>
</div>
<script>
    var User = {
        template: 
        	`<div>
				<h1>User 组件</h1>
				<button @click="goRegister">点击进入注册组件</button>
    		</div>`,
        methods: {
            goRegister: function() {
                this.$router.push('/register');
            }
        }
    }

    var Register = {
        template: 
        	`<div>
				<p>注册组件</p>
				<button @click="goBack">点击返回</button>
    		</div>`,
        methods: {
            goBack: function() {
                this.$router.go(-1);
            }
        }
    }

    var router = new VueRouter({
        routes: [{
            path: '/user',
            component: User
        }, {
            path: '/register',
            component: Register
        }]
    })
    var vm = new Vue({
        el: '#app',
        data: {},
        router: router
    })
</script>

在这里插入图片描述
在这里插入图片描述

Logo

前往低代码交流专区

更多推荐