09vue2

vue

简介

  • 一套用于构建用户界面的前端框架
  • 特性
    • 数据驱动视图:随页面发生变化而变化
    • 双向数据绑定:操作表单,实现开发者在不操作DOM的前提下获取表单元素最新属性
  • MVVM
    • M:Model 数据源
    • V:View DOM结构
    • VM:ViewModel vue实例(核心)

基本使用

  • 导入vue.js的script脚本文件

  • 声明一个将要被vue所控制的DOM区域

  • 创建vm实例对象

    <body>
        <div id='app'></div>
    </body>
    <script>
    	const vm = new Vue({
            el:'#app',
            data: {
                username: 'zhangsan'
            }
        })
    </script>
    

指令

内容渲染指令

v-text
  • 运用在属性节点上

  • 会覆盖原有标签里面的内容,只能渲染纯文本内容

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>v-text</title>
        <link rel="stylesheet" href="lib/bootstrap.css">
    
    </head>
    <body>
        <div id="app">
            <p v-text="gender">性别</p>
        </div>
    </body>
    <!--1、导入vue.js-->
    <script src="lib/vue-2.6.12.js"></script>
    <script>
        <!---->
        //2、创建vue实例对象
        const vm = new Vue({
            //控制哪个区域 el后接选择器
            el: '#app',
            // 渲染页面的数据 data
            data: {
                gender: '女',
            },
          })
    </script>
    </html>
    
{{}}
  • 插值表达式,解决内容覆盖问题,相当于一个占位符

  • 只能渲染纯文本内容

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>{{}}</title>
        <link rel="stylesheet" href="lib/bootstrap.css">
    
    </head>
    <body>
        <div id="app">
         	<p>姓名: {{ username }}</p>
        </div>
    </body>
    <!--1、导入vue.js-->
    <script src="lib/vue-2.6.12.js"></script>
    <script>
        <!---->
        //2、创建vue实例对象
        const vm = new Vue({
            //控制哪个区域 el后接选择器
            el: '#app',
            // 渲染页面的数据 data
            data: {
               username:'zhangsan'
            },
          })
    </script>
    </html>
    
v-html
  • 运用在属性节点上

  • 会覆盖原有标签里面内容,可以渲染带标签的字符串

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>v-html</title>
        <link rel="stylesheet" href="lib/bootstrap.css">
    
    </head>
    <body>
        <div id="app">
         	<div v-html="info">111</div>
        </div>
    </body>
    <!--1、导入vue.js-->
    <script src="lib/vue-2.6.12.js"></script>
    <script>
        <!---->
        //2、创建vue实例对象
        const vm = new Vue({
            //控制哪个区域 el后接选择器
            el: '#app',
            // 渲染页面的数据 data
            data: {
               info:'<h4 style="color: red">22</h4>'
            },
          })
    </script>
    </html>
    

属性绑定指令

v-bind
  • 简写 :

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>v-bind</title>
        <link rel="stylesheet" href="lib/bootstrap.css">
    
    </head>
    <body>
        <div id="app">
         	<input type="text" v-bind:placeholder="tips">
            <input type="text" :placeholder="tips1">
        </div>
    </body>
    <!--1、导入vue.js-->
    <script src="lib/vue-2.6.12.js"></script>
    <script>
        <!---->
        //2、创建vue实例对象
        const vm = new Vue({
            //控制哪个区域 el后接选择器
            el: '#app',
            // 渲染页面的数据 data
            data: {
                tips: '请输入用户名',
                tips1: '请输入密码',
            },
          })
    </script>
    </html>
    

事件绑定指令

v-on
  • 简写 @

  • DOM原生时间onclick、oninput替换为vue绑定事件为v-on:click简写为@click

  • 函数可以传递参数其中不加小括号表示不传参,添加小括号实现传递参数

  • vue原生对象$event

    • $event就是原生DOM的事件对象event
    • 当传递参数是需要将原生对象 e v e n t 传入,当无参数传入时默认传递了 event传入,当无参数传入时默认传递了 event传入,当无参数传入时默认传递了event原生对象
  • 事件修饰符

    • 添加在事件绑定后面
    • 阻止默认行为 @click.prevent === e.preventDefault();
    • 阻止事件冒泡 stop
    • 绑定事件只触发一次 once
  • 按键修饰符

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>v-on</title>
        <link rel="stylesheet" href="lib/bootstrap.css">
    
    </head>
    <body>
        <div id="app">
         	 <p>值:{{ count }}</p>
            <button v-on:click="add">+1</button>
            <button @click="sub(2)">-2</button>
            
            <h4>如果为偶数按钮背景则为红色,如果为奇数则取消背景颜色</h4>
            <p>value:{{ value }}</p>
            <button v-on:click="add1(1, $event)">+1</button>
            <br>
    
            <h4>事件修饰符:打印点击事件阻止链接跳转</h4>
            <a href="www.baidu.com" @click.prevent="show">跳转链接</a>
      
            <h4>按键修饰符:按下esc键清除文本框内容,按下enter打印内容</h4>
            <input type="text" @keyup.esc="clear" @keyup.enter="enter"
        </div>
    </body>
    <!--1、导入vue.js-->
    <script src="lib/vue-2.6.12.js"></script>
    <script>
        <!---->
        //2、创建vue实例对象
        const vm = new Vue({
            //控制哪个区域 el后接选择器
            el: '#app',
            // 渲染页面的数据 data
            data: {
               	count: 0,
               	value: ''
            },
            methods: {
            // 创建函数
                add(){
                // 修改data里面数据:调用vm对象中的data属性的count值  其中this === vm
                ++this.count;
            	},
                sub(n){
                    this.count -= n;
                },
            }
          })
    </script>
    </html>
    

双向绑定指令

v-model
  • 在不操作DOM的前提下快速获取表单数据

  • 只有表单元素使用才有意义

  • 修饰符

    • number:将用户输入字符串转换为数值类型;
    • trim:自动过滤用户首位空白字符;
    • lazy:离开输入框失去焦点才会更新
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>v-model</title>
        <link rel="stylesheet" href="lib/bootstrap.css">
    
    </head>
    <body>
        <div id="app">
         	<p>用户名:{{username}}</p>
            <input type="text" v-model="username1">
            <!--v-model实现复选 选取value值-->
            <select name="" id="" v-model="city">
                <option value="">请选择城市</option>
                <option value="1">北京</option>
                <option value="2">上海</option>
                <option value="3">广州</option>
            </select>
            
             <input type="text" v-model.number="n1"> + <input type="text" v-model.number="n2"> = <span>{{n1+n2}}</span>
        </div>
    </body>
    <!--1、导入vue.js-->
    <script src="lib/vue-2.6.12.js"></script>
    <script>
        <!---->
        //2、创建vue实例对象
        const vm = new Vue({
            //控制哪个区域 el后接选择器
            el: '#app',
            // 渲染页面的数据 data
            data: {
               username:'zhangsan',
               city: ''n1: 1,
               n2: 2,
            },
          })
    </script>
    </html>
    

条件渲染指令

v-if
  • 动态创建或者移除元素
v-show
  • 动态为元素添加或者移除dispaly:none样式,实现元素显示或者隐藏
v-else-if
  • 需要配合v-if使用

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>v-for</title>
        <link rel="stylesheet" href="lib/bootstrap.css">
    
    </head>
    <body>
        <div id="app">
            <!--v-if: 动态的创建或者移除元素-->
            <p v-if="flag">v-if控制的元素</p>
            <!--v-show: 动态为元素添加或者移除dispaly:none样式,实现元素显示或者隐藏-->
            <p v-show="flag">v-show控制的元素</p>
            <!--v-else-if-->
            <p>v-else-if</p>
            <div v-if="type === 'A'">优秀</div>
            <div v-else-if="type === 'B'">良好</div>
            <div v-else-if="type === 'C'">一般</div>
            <div v-else>差</div>
    
        </div>
    </body>
    <!--1、导入vue.js-->
    <script src="lib/vue-2.6.12.js"></script>
    <script>
        <!---->
        //2、创建vue实例对象
        const vm = new Vue({
            //控制哪个区域 el后接选择器
            el: '#app',
            // 渲染页面的数据 data
            data: {
                flag: true,
                type: 'A',
    
            },
        })
    </script>
    </html>
    

列表渲染指令

v-for
  • <tr v-for="(item,index) in list" :key="item.id">

    • 第一个参数item表示列表中循环的元素,第二个参数index代表索引
    • 每使用一个v-for指令都需要绑定一个key属性
    • key属性的值只能时字符串或者数字类型,尽量将id作为key值
    • key的值不能重复,否则报duplicate keys detected错误
    • key值不可以使用索引
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>v-for</title>
        <link rel="stylesheet" href="lib/bootstrap.css">
    
    </head>
    <body>
        <div id="app">
         	 <table class="table table-bordered table-hover table-striped">
                <thead>
                    <th>索引</th>
                    <th>ID</th>
                    <th>姓名</th>
                </thead>
                <tbody>
                    <tr v-for="(item,index) in list" :key="item.id">
                        <td>{{index}}</td>
                        <td>{{item.id}}</td>
                        <td>{{item.name}}</td>
                    </tr>
                </tbody>
            </table>
        </div>
    </body>
    <!--1、导入vue.js-->
    <script src="lib/vue-2.6.12.js"></script>
    <script>
        <!---->
        //2、创建vue实例对象
        const vm = new Vue({
            //控制哪个区域 el后接选择器
            el: '#app',
            // 渲染页面的数据 data
            data: {
            	list: [
                    {id:1, name:'zs'},
                    {id:2, name:'ls'},
                    {id:3, name:'ww'},
                ],
            },
            methods: {
     		    add1(n, e){
                    this.value += n;
                    if (this.value%2 == 0){
                        e.target.style.backgroundColor = 'red';
                    }else {
                        e.target.style.backgroundColor = '';
                    }
                },
    
                show(){
                    console.log('点击了a链接')
                },
    
                clear(e){
                    // 清空文本框
                    e.target.value = '';
                },
                enter(e){
                    console.log(e.target.value);
                }
    
            }
          })
    </script>
    </html>
    

过滤器

  • 使用位置:插值表达式及v-bind属性绑定

  • 通过管道符进行调用

  • 过滤器函数必须定义到filters下,本质上是一个函数 过滤器必须要有一个返回值

  • 过滤器函数形参永远都是管道符前面的值

  • 全局过滤器

    • Vue.filter
    • 全局过滤器放在在上方
  • 私有过滤器

    • 只能在当前vm实例所控制的el区域内使用
    • 通过vue实例的filters节点属性实现
    • 本质上为一个函数,必须有返回值
  • 过滤器可通过串联调用多个过滤器

    • a|b|c|d
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>过滤器</title>
    </head>
    <body>
    
        <h2 style="color: pink">过滤器使用</h2>
        <div id="app">
            <p>message的值是:{{message|capi}}</p>
            <p>message的值是:{{message|capi1}}</p>
        </div>
    
        <div id="app2">
            <p>message的值是:{{message|capi}}</p>
            <p>message的值是:{{message|capi1}}</p>
        </div>
    
    </body>
    
    <script src="lib/vue-2.6.12.js"></script>
    <script>
        // 使用Vue.filter定义全局过滤器
        Vue.filter('capi1', function (str){
            return str.charAt(0).toUpperCase();
        })
    
        const vm = new Vue({
            el: '#app',
            data: {
                message:'hello'
            },
            filters: {
                // 过滤器函数形参中的val永远都是管道符前面的值
                // 定义到filters的过滤器叫做私有过滤器只能自己使用
                capi(val){
                    // charAt接收索引值表示把字符串中的索引对应的字符取出来
                    const first = val.charAt(0).toUpperCase();
                    const other = val.slice(1);
                    return first+other;
                }
            }
        });
    
        const vm2 = new Vue({
            el: '#app2',
            data: {
                message:'hello'
            }
        });
    
    </script>
    </html>
    

侦听器

  • 允许开发者监视数据变化,实现特定动作

  • 所有侦听器必须放在watch节点下

  • 本质上是一个函数 要监视哪个数据的变化就把数据名作为方法名

  • 函数(方法)形式的侦听器

    • 在刚进入页面的时候不会被自动触发 监听对象属性发生变化不会触发监听器
  • 对象格式的侦听器

  • immediate: true

    • 选项默认值为false 当为true时进入页面就会进行触发
  • deep: true

    • 开启深度监听 只要对象中任何一个属性变化都会触发对象监听器
  • 如果要侦听的是对象的子属性则必须包裹一层单引号,类似于函数侦听器

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>侦听器</title>
</head>
<body>
    <div id="app">

        <span>函数形式侦听器</span><input type="text" v-model="username">
        <br>
        <span>对象格式侦听器</span><input type="text" v-model="username1">
        <br>
        <span>监视对象中属性变化</span><input type="text" v-model="info.username">
    </div>
</body>

<script src="lib/jquery-v3.6.0.js"></script>
<script src="lib/vue-2.6.12.js"></script>
<script>
    const vm = new Vue({
        el: '#app',
        data: {
            username: 'user',

            username1: 'user',

            info: {
                username: 'admin'
            }

        },
        methods: {

        },
        watch: {
            // 函数形式侦听器
            // newVal为新值   oldVar为旧值    新值在前旧值在后
            username(newVal, oldVal){
                console.log(newVal + ',   '+ oldVal)
                // if (newVal='') return;
                // // 调用jQuery中的ajax发送请求,判断用户名是否可用
                // $.get('https://www.escook.cn/api/finduser/' + newVal, function (result) {
                //     console.log(result);
                // })
            },

            // 对象格式的侦听器
            username1: {
                // 侦听器处理函数
                handler(newVal, oldVal){
                    console.log(newVal + ',   '+ oldVal)
                },
                // 选项默认值为false  当为true时进入页面就会进行触发
                immediate: true,
                // 开启深度监听 只要对象中任何一个属性变化都会触发对象监听器
                deep: true
            },

            // 对象格式的侦听器
            info: {
                // 侦听器处理函数
                handler(newVal, oldVal){
                    console.log(newVal + ',   '+ oldVal)
                },
                // 开启深度监听 只要对象中任何一个属性变化都会触发对象监听器
                deep: true
            },

            // 如果要侦听的是对象的子属性则必须包裹一层单引号
            'info.username'(newVal, oldVal){
                console.log(newVal,oldVal)
            }

        }
    })


</script>
</html>

计算属性

  • 所有计算属性都要定义到computed节点之下 计算属性在定义的时候都要定义成方法格式

  • 计算属性的本质是一个属性 ,与data中属性使用方法一致

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>计算属性</title>
        <style>
            .box {
                width: 200px;
                height: 200px;
                border: 1px solid black;
            }
        </style>
    </head>
    <body>
    <div id="app">
        <span>r</span><input type="text" v-model.number="r"><br>
        <span>g</span><input type="text" v-model.number="g"><br>
        <span>b</span><input type="text" v-model.number="b">
        <div class="box" :style="{backgroundColor: rgb}">{{rgb}}</div>
    </div>
    </body>
    
    <script src="lib/vue-2.6.12.js"></script>
    <script>
        const vm = new Vue({
            el: '#app',
            data: {
                r: 0,
                g: 0,
                b: 0
            },
            computed: {
                // rgb方法相当于data中属性,与data中属性使用方法一致
                rgb(){
                    // $ 模板字符串
                    return `rgb(${this.r}, ${this.g}, ${this.b})`
                }
            }
        })
    
    </script>
    </html>
    

vue-cli

  • 中文官网:https://cli.vuejs.org/zh/
  • 安装:npm install -g @vue/cli
  • 创建vue:
    • vue create 项目名称
    • 建议选择Manually select features
      • babel:编译器
      • TypeScript:微软
      • Progressive web App(PWA) support:渐进式布局
      • Router:路由
      • CSS Pre-processors:CSS预处理器
      • Linter/Formtter:约束代码风格
      • Unit Testing:单元测试
      • E2E Testing:E2E测试
    • 切换到创建目录
    • 运行项目:npm run serve

src目录结构

  • assets:静态资源 如:css、图片
  • components:程序员封装的可复用组件
  • main.js:项目入口文件
  • App.vue:项目跟组件

组件

组件三部分

  • template:模板结构

    • 必须存在
    • 只起到包裹性质的作用,不会渲染成真正的DOM元素
    • 只能包含唯一节点
  • script:行为

    • 组件中的相关data数据、methods方法等都需要定义到export defasult所导出的对象中
    • 格式为 export default {}
    • 其中data必须为函数,不能直接指向一个数据对象,通过return返回数据对象
  • style:样式

    • 添加less语法:在style标签中添加lang="less"属性
  • 组件关系

    • 父子关系
    • 兄弟关系

组件使用

  • 注册组件
    • 全局组件
      • 在main.js入口文件中使用import导入需要的组件
      • 通过Vue.component(参数1,参数2) 注册组件
        • 参数1:字符串格式,表示组件的注册名称
        • 参数2:需要被全局注册的那个组件
    • 私有组件
      • 在需要使用该组件的vue文件中通过import导入组件
      • 通过components节点注册组件
  • 以标签的形式使用注册的组件

组件样式冲突

  • 实现组件内部样式只影响该组件的使用
  • 方法1
    • 给当前组件模板结构中所有标签都加上同意属性 data-v-001
    • 使用时带上该属性 如:h3[data-v-001]
  • 方法2
    • 给当前组件中style节点加入scoped属性:<style scoped></style>
    • 该方式类似于h3[data-v-001]
  • 样式穿透
    • 更改子组件
    • 在需要改变的子组件样式前添加/deep/前缀 :/deep/h5
    • 该方式类似于[data-v-001] h5

生命周期

创建阶段
  • 创建对象new Vue()
  • beforCreate
    • props/data/methods尚未被创建
  • created
    • props/data/methids被创建
    • 调用methods中的方法发起ajax请求拿数据
  • beforeMount
    • 生成模板结构,但DOM还未生成
  • mounted
    • 生成DOM结构操作DOM元素
运行阶段
  • 最少被执行0次,只有数据发生改变才会执行
  • beforeUpdate
    • 当数据发生改变执行此时页面为旧的,数据为新的
  • updated
    • 实现数据与界面同步
销毁阶段
  • beforeDestory
  • destoryed

数据共享

父传子
  • 通过自定义属性props实现

  • 子组件中封装 props:[‘自定义属性A’,‘自定义属性B’]

    • 数据可直接在模板结构中使用
    • 只读属性,不能直接修改props的值,否则报错
    • 若要改变自定义属性的值一般在data属性中将this.自定义属性赋值给一个接收对象,通过调用接收对象实现值的修改
    • 其中可为属性添加配置选项
      • props: {自定义属性A: {配置选项}, 自定义属性B: {配置选项}}
      • 该组件被使用时,如果没有传递自定义属性,则可通过defalut设置默认值
      • 自定义属性也可以通过type属性定义该值的类型
      • 当添加requred: ture 属性后,若父组件不传递值则会报错
  • 父组件中在子组件对于标签中配合v-bind属性实现

  • 例如子组件为Left.vue,父组件为App.vue

  • 子组件:

    <template>
    	<div class='left-container'>
            <h3>子组件</h3>
    		<p>msg的值为:{{msg}}</p>
    		<p>user对象:{{user}}</p>
    		<p>姓名:{{user.username}}</p>
    	</div>
    </template>
    
    <script>
    	export default {
            props:['msg',['user']]
        }
    </script>
    
    <style>
        .left-comtainer {
            样式
        }
    </style>
    
  • 父组件

    <template>
    	<div class='app-container'>
            <h3>父组件</h3>
            <div class="box">
                <Left :msg="message" :user="userinfo"></Left>
        	</div>
        </div>
    </template>
    
    <script>
        import Left from "@/components/Left";
        
    	export default {
            components:{
    			Left,
        	},
            data() {
                message: 'hello',
                userinfo: {username:'wsc', age: 18}
            }
        }
    </script>
    
    <style>
        .left-comtainer {
            样式
        }
    </style>
    
子传父
  • 通过自定义事件来实现

  • 子组件通过this.$emit实现

    • this.$emit(“自定义事件名称”,传递参数)
  • 父组件配合v-on实现

    • 在调用的子组件标签中添加@自定义事件名称=“方法名”
    • 在methods中添加方法 方法名(参数){ }
  • 例如子组件为Right.vue,父组件为App.vue

  • 子组件:

    <template>
    	<div class='left-container'>
            <h3>子组件---{{ count }}</h3>
           	<button @click="add">+1</button>
    	</div>
    </template>
    
    <script>
    	export default {
            data() {
                return {
                    count: 0
                }
            },
           	methods: {
                add(){
                    this.count+=1
                    this.$emit('numChage', this.count)
                }
            }
        }
    </script>
    
    <style>
        .left-comtainer {
            样式
        }
    </style>
    
  • 父组件

    <template>
    	<div class='app-container'>
            <h3>父组件---{{ countFronSon }}</h3>
            <div class="box">
                <Right @numChange="getNewCount"></Right>
        	</div>
        </div>
    </template>
    
    <script>
        import Right from "@/components/Right";
        
    	export default {
            data() {
                return: {
    				// 获取子组件的值
                    countFromSon: 0
                }
            },
            components:{
    			Right,
        	},
            methods: {
                getNewCount(val){
                    this.countFromSon = val
                }
            }
        }
    </script>
    
    <style>
        .left-comtainer {
            样式
        }
    </style>
    
兄弟传值
  • 通过EventBus进行数据共享

  • 创建eventBus.js模块,并向外共享一个Vue实例对象

    import Vue form 'vue'
    // 向外共享Vue实例对象
    export default new Vue()
    
  • 在数据发送方,通过bus.$emit(‘事件名称’, 要发送的数据)触发自定义事件

    <template>
    	<div class='app-container'>
            <h3>发送方</h3>
           	<button @click="sendMsg">发送数据</button>
        </div>
    </template>
    
    <script>
        import bus from "./eventBus.js";
        
    	export default {
            data() {
                return: {
                    dataMsg: '需要发送的数据'
                }
            },
            methods: {
                sendMsg(){
                    bus.$emit('share', this.dataMsg)
                }
            }
        }
    </script>
    
    <style>
        .left-comtainer {
            样式
        }
    </style>
    
  • 在数据接收方,调用bus.$on(‘事件名称’, 事件处理函数)方法注册一个自定义事件

    <template>
    	<div class='app-container'>
            <h3>接收方</h3>
           	<p>{{msgFromSend}}</p>
        </div>
    </template>
    
    <script>
        import bus from "./eventBus.js";
        
    	export default {
            data() {
                return: {
                    msgFromSend: ''
                }
            },
           created() {
               bus.$on('share', val => {
                   this.msgFromSend = val
               })
           }
        }
    </script>
    
    <style>
        .left-comtainer {
            样式
        }
    </style>		
    

ref引用

  • 在不通过原生方法操作DOM的情况下,获取DOM元素和组件的引用

  • $refs

    • vue组件实例中都包含一个$refs对象
    • DOM元素的引用
    <template>
    	<div class='app-container'>
            <h3 ref='hsRef'>根组件</h3>
           	<button @click='show'>点击实现样式改变</button>
        </div>
    </template>
    
    <script>
    	export default {
           methods: {
               show(){
                   this.ref.h3Ref.style.color = 'red'
               }
           }
        }
    </script>
    
    <style>
        .app-comtainer{ 
            样式
        }
    </style>		
    
  • 组件引用

    • 子组件
    <template>
    	<div class='left-container'>
            <h3>子组件</h3>
            <p>count: {{ count }}</p>
            <button @click="cpunt+=1">+1</button>
            <button @click="resetCount">重置</button>
    	</div>
    </template>
    
    <script>
    	export default {
            data() {
                return {
                    count: 0
                }
            },
           	methods: {
                resetCount(){
                    this.count = 0
                }
            }
        }
    </script>
    
    <style>
        .left-comtainer {
            样式
        }
    </style>
    
    • 父组件
    <template>
    	<div class='app-container'>
            <h3>父组件</h3>
            <button @click='resetCount'>重置子组件count</button>
           	<Left ref='comLeftRef'></Left>
        </div>
    </template>
    
    <script>
        import Left from "@/components/Left";
        
    	export default {
            components:{
    			Left,
        	},
            methods: {
                resetCount(){
                    this.$refs.comLeftRef.count = 0
                    
                   	// 也可以调用子组件中的方法进行实现
                    // this.$refs.comLeft.resetCount()
                }
            }
        }
    </script>
    
    <style>
        .left-comtainer {
            样式
        }
    </style>
    
  • this.$nextTick(cb)

    • 实现将cb回调推迟到下一个DOM更新周期进行执行
    • 保证cb回调函数可以操作到最新的DOM元素
    <template>
    	<div class='app-container'>
            <h3>父组件</h3>
            <input type='text' @blur="showButton" ref='inputRef' v-if='inputVisible'>
            <button @click='showInput' v-else>展示输入框</button>
        </div>
    </template>
    
    <script>
    	export default {
    		data() {
                return {
                    // 默认隐藏输入框
                    inputVisibler: false
                }
            }
            methods: {
               showButton() {
               		this.inputVisibler = false
               },
               showInput() {
                   	this.inputVisibler = true
                   	// 展示后自动获取焦点
                   this.$nextTick(() =>{
                       this.$refs.inputRef.focus()
                   })
               }
            }
        }
    </script>
    
    <style>
        .left-comtainer {
            样式
        }
    </style>
    

动态组件

  • 动态实现组件的显示与隐藏

  • component

    • 相当于一个占位符,实现组件的显示与隐藏
    • 其中is属性可动态指定需要渲染的组件
  • keep-alive

  • 保持动态组件状态,防止组件被销毁,把内部组件进行缓存

  • 当组件被缓存时会自动触发组件的deactivated生命周期函数

  • 当组件被激活时会自动触发组件的activated生命周期函数

  • deactivated与activated函数只有在使用keep-alive标签才具有作用

  • 当组件第一次被创建时,会触发created生命周期,也会触发activated生命周期

  • 当组件再次被激活时,不会触发created生命周期,会触发activated生命周期

  • include

    • 只有指定组件可被缓存 <keep-alive include: “组件名称”>
    • 当组件不提供name属性,则注册名默认为组件名
    • 当组件提供了name顺序,调用组件时则需要使用name属性定义的名称
      • 例如:name: ‘yaya’ 调用:<keep-alive include: “yaya”>
    • exclude指定的组件不可被缓存,两者不能同时使用
<template>
	<div class='app-container'>
        <h3>父组件</h3>
        <keep-alive include="Left">
    		<component :is="comName"></component>
    	</keep-alive>
        <button @click="comName ='Left'">展示Left组件</button>
        <button @click="comName ='Right'">展示Right组件</button>
    </div>
</template>

<script>
    import Left from "@/components/Left";
    import Right from "@/components/Right";
    
	export default {
		data() {
            return {
                // 默认展示Left组件
                comName: 'Left'
            }
        },
         components:{
			Left,
        	Right
    	}
    }
</script>

<style>
    .left-comtainer {
        样式
    }
</style>

插槽

  • 在组件封装期间为用户预留的内容占位符

  • <slot>定义插槽

    • <slot name="default">
    • 每一个slot都会有一个名称,若不写默认为default
    • 其中带名称的插槽称之为具名插槽
    • 在封装中可以对外传递数据,数据存放在<slot>标签中
      • 例如<slot name="contentSlot" msg="hello vue.js"></slot>
      • 这种称之为作用域插槽
    <template>
    	<div class='left-container'>
            <h3>Left 组件</h3>
            
            <slot name="default">这是default插槽默认内容</slot>
            
            <div>
                <slot name="contentSlot" msg="hello vue.js"></slot>
        	</div>
        </div>
    </template>
    
    <script>
    	export default {
    	
        }
    </script>
    
    <style>
        .left-comtainer {
            样式
        }
    </style>
    
  • 为插槽提供内容

    • <template>元素上使用v-slot指令,并以v-slot的参数的形式提供名称
      • 例:<template v-slot="default"></template>
      • 其中template只起包裹作用
      • v-slot只能使用在template属性上
      • v-slot可简写为 #
      • 在接收作用域插槽时可通过#插槽名称="scope"接收
        • 接收为一个对象
        • 若不传则为一个空对象
        • 调用方式scope.键
        • 接收时也可通过结构赋值的方式简化数据的接收过程
          • 例: <template #contentSlot="{{scope.msg}"></template>
    <template>
    	<div class='left-container'>
            <h3>App 组件</h3>
            
            <Left>
                <template v-slot:default></template>
        		<template #contentSlot="scope">
    				<p>  {{ scope.msg }}  </p>
    			</template>	
        	</Left>
        </div>
    </template>
    
    <script>
    	export default {
    	
        }
    </script>
    
    <style>
        .left-comtainer {
            样式
        }
    </style>
    

自定义指令

  • 私有自定义指令

    • 在vue组件中,在directives节点下声明私有自定义指令
  • 全局自定义指令

    • 在main.js文件中通过Vue.directive()可实现对全局自定义指令
  • 使用

    • 在使用时需要添加 v- 前缀
    • 在使用时通过 = 可为当前指令进行动态绑定参数值
    <template>
      <div class="app-container">
        <h1 v-color>App根组件</h1>
        <p v-color1="color1">自定义组件</p>
    <!--    在双引号中再包裹一层单引号表示引用具体数据,不包裹则表示引用对应属性的值(键获取值)-->
        <p v-color1="'red'">自定义组件1</p>
    
    <!--    改变div的背景颜色-->
        <div class="box" v-backgroundColor="backgroundColor"></div>
        <button @click="show">改变div颜色</button>
    
    
      </div>
    </template>
    
    <script>
    import Left from "@/components/Left";
    import Right from "@/components/Right";
    import Article from "@/components/Article";
    export default {
    
      data() {
        return {
          color1: 'blue',
          backgroundColor: 'pink'
        }
      },
    
      components: {
        Left,
        Right,
        Article
      },
    
      methods: {
        show(){
          this.backgroundColor = 'blue'
        }
      },
    
      // 私有指令
      directives: {
        // 定义一个color指令指向一个配置对象
        color: {
          // 当指令第一次绑定到元素上时会触发bind函数
          // 形参中的el表示当前指令所绑定的那个DOM对象
          bind(el){
            el.style.color = 'red'
    
          }
        },
        color1: {
          // binding为接收对象,其中binding.value则为调用时等号所调用的值
          bind(el, binding){
            el.style.color = binding.value
          }
        },
    
        // backgroundColor: {
        //   // 第一次绑定时候执行,之后不在执行
        //   bind(el,binding){
        //     el.style.backgroundColor = binding.value
        //   },
        //   // 第一次不执行,在DOM结构更新的时候会触发update函数
        //   update(el,binding){
        //     el.style.backgroundColor = binding.value
        //   }
        // }
        // 当bind和update逻辑完全一样可实行简写形式
        backgroundColor(el,binding){
          el.style.backgroundColor = binding.value
        },
      }
    
    }
    </script>
    
    <style lang="less">
      .app-container {
        padding: 1px 20px 20px;
        background-color: #efefef;
      }
      .box {
        height: 200px;
        width: 200px;
      }
    </style>
    
    import Vue from 'vue'
    import App from './App.vue'
    
    Vue.config.productionTip = false
    
    // 全局自定义指令
    
    // 当bind和update逻辑完全一样可实行简写形式
    Vue.directive('color111', function (el, binding) {
      el.style.color = binding.value
    })
    
    Vue.directive('color112', {
      bind(el, binding) {
        el.style.color = binding.value
      },
      update(el, binding) {
        el.style.color = binding.value
      },
    
    })
    
    new Vue({
      render: h => h(App),
    }).$mount('#app')
    

路由

  • SPA:在web网站中只有唯一一个HTML界面

  • 在SPA项目中进行不同功能之间的切换需要通过前端路由实现、

  • 路由:Hash地址与组件之间的对应关系

  • vue-router

    • 官方网址:https://router.vuejs.org/zh/
    • vue2中安装:npm install vue-router@3.5.2
    • 创建路由模块:在src源代码目录中,新建router/index.js路由模块,初始化代码如下
    // src/router/index 就是当前项目的路由模块
    // 1、导入vue就vue-router包
    import Vue from "vue";
    import VueRouter from "vue-router";
    
    // 2、调用Vue.use()函数,把VueRouter安装为Vue的插件
    // Vue.use()作用安装插件
    Vue.use(VueRouter)
    
    // 3、创建路由实例对象
    const router = new VueRouter({})
    
    // 4、向外共享路由实例对象
    export default router
    
    • 将导入的路由模块挂载到src/main.js入口文件中
    import Vue from 'vue'
    // 更改路径通过App2实现路由
    import App from './App2.vue'
    // 1、导入路由模块
    // 在模块化导入时如果给定的为文件夹,则默认导入文件夹下index.js文件
    import router from "@/router";
    
    Vue.config.productionTip = false
    
    new Vue({
      render: h => h(App),
      // 在Vue项目中要想实现路由,必须通过下列方式实现挂载
      // 2、router: 路由的实例对象,当属性名和实例对象一致时可进行简写为router
      router
    }).$mount('#app')
    
    
    • 路由链接
      • <router-link to='"/home">首页</router-link>
      • 在斜线(/)后的参数称之为路径参数,通过this.$route.params进行获取
      • 在哈希地址中问号(?)后面的参数称之为查询参数,通过this.$route.query进行获取
      • this.$route.path获取哈希路径
      • this.$route.fullPath获取完整地址
      • router-link相当于a链接中的a标签
      • to相当于a链接中的href属性
    • 占位符
      • <router-view></router-view>
  • 路由规则

    • 在src/router/index.js路由模块中,创建VueRouter时通过routers数组声明路由规则
    • 实现Hash地址与组件之间对应关系
    • 其中对应的组件需要通过import导入
    • path表示匹配的hash地址,component表示需要展示的路由组件
    • 重定向:redirect 实现界面跳转的指定页面
    // src/router/index 就是当前项目的路由模块
    // 1、导入vue就vue-router包
    import Vue from "vue";
    import VueRouter from "vue-router";
    
    // 导入需要的组件
    import Home from "@/components/Home";
    import Movie from "@/components/Movie";
    
    // 2、调用Vue.use()函数,把VueRouter安装为Vue的插件
    // Vue.use()作用安装插件
    Vue.use(VueRouter)
    
    // 3、创建路由实例对象
    const router = new VueRouter({
        // 定义Hash地址和组件之间的对应关系
        routes:[
            // 路由规则
            // 重定向:redirect
            {path: '/', redirect:'/home'},
            {path: '/home', component:Home},
            {path: '/movie/', component:Movie},
        ]
    })
    
  • 嵌套路由

    • 通过chindren属性声明子路由规则
    • 如果children中,某个路由规则的puth值为空字符串,则这条路由规则为默认子路由
    • 默认子路由相当于进行了redirect重定向只是不存在跳转
    {
         path: '/about',
         component:About,
         // 子路由规则   children属性
         children: [
         	// 默认子路由相当于redirect重定向
            {path:'',component:Tab1},
            {path:'tab1',component:Tab1},
            {path:'tab2',component:Tab2}
         ],
         // redirect:'/about/tab1'
     },
    
  • 动态路由

    • 为提高路由规则的复用性,把Hash地址中可变部分定义为参数项
    • 通过英文冒号定义路由的参数项
    • 获取参数方式
      • 方式1:在组件中可通过this.$route.parans.id 获取参数
      • 方式2:在当前路由规则中开启props传参,在组件中通过props: [‘id’]获取参数
        • 路由规则 {path: ‘/movie/:id’, component:Movie, props:true}
        • 获取参数 props: [‘id’]
    • route为路由的参数对象
  • 编程式导航

    • 通过API实现的导航
    • router为路由的导航对象
    • this.$router.push(‘hash地址’)
      • 跳转到指定的hash地址,并添加一条历史记录
    • this.$router.replace(‘hash地址’)
      • 跳转到指定的hash地址,并替换当前的历史纪录
    • this.$router.go(数值)
      • 数据为几表示前进或者倒退多少
    • this.$router.back()
      • 后退一层
    • this,$router.forward()
      • 前进一层
  • 导航守卫

    • 控制路由的访问权限
    // src/router/index 就是当前项目的路由模块
    // 1、导入vue就vue-router包
    import Vue from "vue";
    import VueRouter from "vue-router";
    
    // 2、调用Vue.use()函数,把VueRouter安装为Vue的插件
    // Vue.use()作用安装插件
    Vue.use(VueRouter)
    
    // 3、创建路由实例对象
    const router = new VueRouter()
    
    // 为router实例对象,声明全局前置导航守卫
    // 只要发送了路由的导航跳转必然会触发回调函数
    router.beforeEach(function (to,from,next) {
        // to表示将要访问的路由信息
        // console.log(to)
        //from表示将要离开的路由信息对象
        // console.log(from)
        // next()函数表示放行
        // next()
    
        // 当用户拥有后台主页访问权限,直接放行next()
        // 当用户没有后台主页访问权限,强制跳转到其他界面next('/login')
        // 当用户没有后台主页访问权限,不允许跳转到后台主页next(false)
    
        // a、拿到用户将要访问的hash地址
    
        // b、判断hash地址是否等于/main   如果等于则需要登录才能访问   如果不等于则不需要登录直接放行
        if (to.path === '/main'){
            // c、读取localStorage中的token值 如果有token则放行  如果没有则强制跳转到/login登录界面
            const token = localStorage.getItem('token')
            if (token){
                next()
            }else {
                next('/login')
            }
        }else{
            next()
        }
    
    })
    
    // 4、向外共享路由实例对象
    export default router
    
  • 37
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值