Vue.js

1、概念

Vue 是用于构建界面的javascript 库,渐进式JavaScript框架。

对比, jquery是以dom操作为中心javascript库。

vue 是以数据驱动为主javascript库。

数据改变更新页面,页面改变更新数据,vue 是数据双向绑定的框架。

bootstrap 是响应式框架 (ui响应式)

vue 也是响应式框架(data响应式)

2、声明式编程 (注重结果)
<div  id="app">
      <button  v-on:click="foo">点击按钮</button>
</div>

<script>
    new Vue({
         el:"#app",
         methods: {
                foo(){ console.log("触发了点击事件")}
         }
    })
</script>
3、命令式编程 (注重过程)
<div  id="app">
      <button  v-on:click="foo">点击按钮</button>
</div>
<script>
    let button  = document.querySelector("#app button");
   button.onclick = function(){
  		 console.log("触发了点击事件")
   }
</script>
4、data响应式

vue@2版本,采用defineProperty方法实现,监听数据的改变。

<div id="root">
    <input type="text" class="inp">
    <h3 class="title"></h3>
</div>

<script>
    // 获取标签
    const inp_element = document.querySelector("#root input")
    const title_element = document.querySelector("#root .title")
    // 数据
    let data = {
        text: ""
    }
    // 定义储存器变量 (意义就是储存数据)
    // let _text = "";
    // 观察data的text属性的改变
    Object.defineProperty(data,"text", {
        // 读
        get(){
            // console.log("读取text")
            return this._text;
        },
        // 写
        set(value){
            // console.log("写入text")
            this._text = value;
            // 更新页面
            title_element.innerText = inp_element.value;
        }
    })
    // 赋值表示写入 (带等于号)
    // data.text = "123";
    // 读取
    // console.log(data.text);
    // 数据双向绑定
    // 1: 数据改变更新页面
    // 2: 页面更新改变数据
    inp_element.oninput = () => {
        // 改变数据
        data.text = inp_element.value;
    }
</script>

5、Vue基本语法

5.1) 创建vue实例

<!-- 设置挂载点 -->
<div id="app">
    {{color}}
</div>

<!-- 引入vue框架文件 -->
<script src="./libs/vue@2.7.16/vue.js"></script>
<script>
    // 创建vue实例
    // 选项式开发
    // const option = {}


    // 不想看到控制台输出日志信息
    Vue.config.productionTip = false;


    // 声明常量记录vue实例
    const vm = new Vue({
        // 挂载容器
        el: "#app",
        // 在哪添加数据? 在data中添加
        // data:{
        //     color: "red",// vue实例中
        // }
        // 以后经常看到的是这种写法,组件中的数据是独立的
        data(){
            return {
                color: "red"   
            }
        },
    })

    // 检查vue实例
    // console.log(vm);

    // MVVM: 是一种软件设计模式
    // MVVM是Model-View-ViewModel的简写。它本质上就是MVC的改进版。
    // MVVM模式有助于将应用程序的业务和表示逻辑与用户界面 (UI) 清晰分离。 
    // 保持应用程序逻辑和UI之间的清晰分离有助于解决许多开发问题,并使应用程序更易于测试、维护和演变。

5.2) 模板语法 {{}}

<!-- 插值表达式 {{ js }} -->
<div id="app" v-cloak>
    <h2>{{123}}</h2>
    <!-- 报错 直接填写abc, 既不是字符串,也不是变量 -->
    <!-- <h2>{{abc}}</h2> -->
    <h2>{{'abc'}}</h2>
    <!-- 可以书写三元运算 -->
    <h2>{{typeof 'abc' === 'string' ? '字符串类型':'其他类型'}}</h2>
    <!-- 可以填写变量 -->
    <h2>{{title}}</h2>
  

</div>
<script src="./libs/vue@2.7.16/vue.js"></script>
<script>
    //禁止控制台输出日志信息
    Vue.config.productionTip = false;
    new Vue({
        //挂载容器
        el: "#app",
        // 添加属性
        data: {
            title: "标题2222"
        }
    })
</script>

5.3) 指令

设置文本

v-text
v-html

设置属性

v-bind

设置数据双向绑定

v-model

条件渲染

v-show
v-if

列表渲染

v-for

事件绑定

v-on:click="foo"
@click="foo"

自定义指令

<div id="app">
    <!-- 渲染纯文本 -->
    <h2 v-text="`hello title`"></h2>
    <hr>
    <h3 v-mytext="2024"></h3>

    <!-- 设置属性 -->
    <hr>
    <div v-bind:class="`red`"></div>
    <hr>
    <div v-mybind:class="`blue`"></div>
    <hr>
    <!-- 定义一个改变字体颜色的指令可以吗? 肯定可以 -->
    <h2 v-color="`purple`">你好,世界</h2>

</div>
<script src="./libs/vue@2.7.16/vue.js"></script>
<script>
    // 当文档上指令满足不了我们的需求,可以选择自定义指令
    // 1) 注册全局指令
    Vue.directive('color', {
        // 当被绑定的元素插入到 DOM 中时……
        inserted: function (el,option) {
            if(typeof el === 'object'){
                el.style.color = option.value;
            }
        }
    })

    //禁止控制台输出日志信息
    Vue.config.productionTip = false;
    new Vue({
        //挂载容器
        el: "#app",
        // 2)局部自定义指令
        directives: {
            // 名称
            mytext: {
                //定义指令
                inserted(el, option) {
                    // console.log(el, option);
                    if (typeof el === 'object') {
                        el.innerHTML = option.value;
                    }
                }
            },
            // 动态绑定属性(仅仅class属性)
            mybind: {
                inserted(el, option) {
                    console.log(el, option);
                    // 检查el是否为dom对象
                    if (typeof el === 'object') {
                        // 获取属性
                        let arg = option.arg;
                        // 判断
                        if (arg == "class") {
                            el.className = option.value;
                        }
                    }
                }
            }
        }
    })

5.4)事件

v-on:事件类型=“方法”
@事件类型=“方法”

事件修饰符

<div id="app">
    <!-- 阻止事件冒泡 -->
    <div @click="f1">
        <ul @click.stop="f2">
            <li @click.stop="f3"></li>
        </ul>
    </div> 
    <!-- 属于捕获阶段  元素事件触发顺序是从外到内 -->
    <!-- .capture.stop 阻止事件捕获 -->
    <!-- <div @click.capture.stop="f1"> -->
    <!-- 
        <div @click.capture="f1">
            <ul @click.capture="f2">
                <li @click.capture="f3"></li>
            </ul>
        </div> 
    -->

    <!-- 键盘行为 -->
    <input v-model="keywords" type="text" placeholder="请输入关键字" @keydown="getInputVal">
    <br>
    <!-- @keydown.a  按下键盘a按键触发行为 -->
    <!-- @keydown.enter  按下键盘回车按键触发行为 -->
    <input v-model="v1" type="text" placeholder="请输入关键字" @keydown.enter="getInputText">
</div>

<script src="./libs/vue@2.7.16/vue.js"></script>
<script>

    // 实现按下回车按键获取输入框的值

    //禁止控制台输出日志信息
    Vue.config.productionTip = false;
    new Vue({
        //挂载容器
        el: "#app",
        data: {
            keywords: "",
            v1: "",
        },
        methods: {
            f1(){ console.log("div")},
            f2(){ console.log("ul")},
            f3(){ console.log("li")},
            getInputVal(event){
                // console.log(event)
                // 解构赋值
                let { code } = event;
                if(code === "Enter") {
                    console.log("值:",this.keywords);
                }
            },
            getInputText(){
                console.log("值:",this.v1);
            }
        }
    })
</script>

5.5) 属性计算、属性监听、属性过滤

属性计算

<div id="app">
    <div class="container mt-3">
         <div class="row">
            <div class="col-4">
                <input v-model="firstName" type="text" class="form-control" placeholder="请输入姓">
            </div>
            <div class="col-4">
                <input v-model="lastName" type="text" class="form-control" placeholder="请输入名">
            </div>
            <div class="col-4">
                <span style=" font-size: 22px;text-decoration: underline;">{{fullName}}</span>
            </div>
         </div>
    </div>
    <hr>
    <div class="container">
         <input class="form-control" type="number" v-model="num">
         <button class="btn btn-success mt-2">计算 {{num}} 乘以 2 等于 {{doubleValue}} </button>
    </div>

</div>
<script src="./libs/vue@2.7.16/vue.js"></script>
<script>
    //禁止控制台输出日志信息
    Vue.config.productionTip = false;
    new Vue({
        //挂载容器
        el: "#app",
        // 设置数据
        data: {
            firstName: "",// 姓
            lastName: "",//名
            num: 0
        },
        // 属性计算 (只读不写)
        // 例如: fullName , doubleValue这些属性是不可以修改的
        // 错误:  this.fullName = "xxx"
        // 此处是对象
        computed: {
            // 在这个对象中写方法,这个方法名称就可以作为属性,retrun的值就是计算的结果
            // 全名
            // fullName: {
            //     get(){
            //         return this.firstName + this.lastName
            //     }
            // },
            fullName(){
                return this.firstName + this.lastName;
            },
            // 获取双倍的值
            doubleValue(){
                return this.num * 2;
            }
        }

    })
</script>

属性监听

<div id="app">
    <div class="container mt-3">
        <input v-model="city" type="text" placeholder="请输入城市" class="form-control">
    </div>

    <div class="container mt-3">
        <ul>
            <li @click="play(1)">歌曲1</li>
            <li @click="play(2)">歌曲2</li>
            <li @click="play(3)">歌曲3</li>
            <li @click="play(4)">歌曲4</li>
        </ul>
    </div>
    <div class="container mt-3">
        <button @click="addAge" class="btn btn-success">改变用户年龄</button>
    </div>

</div>
<script src="./libs/vue@2.7.16/vue.js"></script>
<script>
    // 属性侦听
    // 主要是观察数据的变化,只要数据发生改变,就执行相关的回调函数
    // data、路由等数据发生改变,就可以执行对应的回调,往往用于处理一些异步的操作
    // 例如: 根据城市名称查询天气信息,根据歌曲id获取歌曲信息

    //禁止控制台输出日志信息
    Vue.config.productionTip = false;
    new Vue({
        //挂载容器
        el: "#app",
        data: {
            city: "广州",
            music_id: "",
            user: {
                age: 20
            }
        },
        // 侦听器
        // 侦听器、属性侦听不是计算结果,不用写return 
        // 这些回调函数的名称就是属性名称,例如data: {city: music_id,user 。。。。}
        watch: {
            // 观察city属性的变化
            // nValue(改变之后的数据),oValue(改变之前的数据) 可选参数
            city(nValue,oValue){
                console.log("观察city是否发生改变....")
                console.log({nValue,oValue})
            },
            music_id: {
                handler(nValue,oValue){
                    console.log("观察music_id是否发生改变....",nValue)
                }
            },
            // 遇到引用数据类型的时候,考虑使用深度侦听
            user:{
                deep: true,// 深度侦听
                immediate: true, // 立即执行
                handler(nValue,oValue){
                    console.log("观察user.age是否发生改变....",nValue.age)
                }
            }
        },
        // 设置方法
        methods: {
            play(id){
                this.music_id = id;
            },
            addAge(){
                this.user.age ++;
            }
            
        }
    })
</script>

属性过滤

<div id="app">
    <div class="container mt-3">
         <h3>{{str}}</h3>
         <h3>{{str | xxx }}</h3>
         <h3>{{str | yyy }}</h3>
         <h3>{{str | xxx | zzz }}</h3>
    </div>

</div>
<script src="./libs/vue@2.7.16/vue.js"></script>
<script>


    //禁止控制台输出日志信息
    Vue.config.productionTip = false;
    new Vue({
        //挂载容器
        el: "#app",
        data: {
            str: "abc123efg456"
        },
        // 过滤器
        // 就是可以作为工具函数来使用哦~~~
        // 通过 “|” 填写过滤器,让其执行相关的回调函数,在函数作用域中可以把处理结果返回
        filters: {
            // 编写xxx回调函数
            xxx(value){
                // console.log(this);// window
                // 去掉所有数字字符
                return value.replace(/\d/g,'');
            },
            yyy(value){
                // console.log(this);// window
                // 去掉所有字母字符
                return value.replace(/[a-z]/ig,'');
            },
            zzz(value){
                // 把字母转大写
                return  value.toUpperCase();
            }
        }
    })
</script>

5.6)生命周期、钩子函数

程序从创建到销毁的过程,我们叫做生命周期。

主要是让我们知道,在不同阶段可以做不同事情。

人的生命周期: 少年、青年、中年、老年

Vue的生命周期: 创建阶段、挂载阶段、更新阶段、销毁阶段

在不同的阶段提供了不同的回调函数(钩子函数)

<div id="app">
    <h2>数字: <span>{{num}}</span></h2>
    <div ref="box">hello world</div>
    
</div>
<script src="./libs/vue@2.7.16/vue.js"></script>
<script>


    //禁止控制台输出日志信息
    Vue.config.productionTip = false;
    const vm = new Vue({
        //挂载容器
        el: "#app",
        // 设置数据
        data: {
            num: 0,
            timer: null
        },
        // 生命周期: 程序从创建到销毁的过程。注意回调函数先后顺序....
        // 钩子函数: 指的是回调函数,生命周期的钩子函数(在vue@2中有8个生命周期的钩子函数)
        // 1) 创建阶段
        // 创建之前执行的钩子函数
        beforeCreate(){
            console.log("1:",this.num);
        },
        // 创建后执行的钩子函数  (初始化数据)
        created(){
            console.log("2:",this.num);
            console.log(this.$refs.box);// undefined
            // 初始化
            // 问题:此处定时器函数不箭头函数,应该注意什么?
            this.timer = setInterval(()=> {
                if(this.num == 5) {
                   clearInterval(this.timer);
                   return ;
                }
                ++ this.num;
            },1000)
        },

        // 2)挂载阶段
        // 挂载之前执行的钩子函数
        beforeMount(){
            console.log("3:",this.num);
            console.log(this.$refs.box);// undefined
        },
        // 挂载后执行的钩子函数 (DOM操作)
        mounted(){
            console.log("4:",this.num);
            console.log(this.$refs.box);// <div>hello world</div>
            // 为了让dom操作更加稳定,可以在此处执行$nextTick回调函数
            // 为了减少报错,所以调用$nextTick回调函数
            this.$nextTick(()=>{
                // 判断程序中是否存在这个标签
                if(this.$refs.box){
                    // 进行dom操作
                    this.$refs.box.style.color = "red";
                    this.$refs.box.style.fontSize = "20px";
                }                   
            })
        },

        // 3)更新阶段
        // 要数据发生改变才执行的回调函数
        beforeUpdate(){
            console.log("5:",this.num);
        },
        updated(){
            console.log("6:",this.num);
        },

        // 4)销毁阶段
        // 程序不存在了,或者以后卸载组件,(显示|隐藏 v-if="false")
        beforeDestroy(){
            console.log("7:",this.num);
        },
        destroyed(){
            console.log("8:",this.num);
        }

    })

    // 为了看得见销毁阶段的钩子函数被执行,可以调用销毁方法
    // vm.$destroy();

    // 通过定时器函数
    // const t = setInterval(()=>{
    //     // 修改数据
    //     vm.num ++;
    // },1000)
</script>

5.7)组件、组件传值

组件是可复用的 Vue 实例.

组件可以是指项目中某个功能,或者页面的某个区块。

例如:按钮,下拉菜单,轮播图,弹窗.....

<div id="app">
    <el-button></el-button>
    <!-- <ElSearch></ElSearch> 错误的 -->
    <el-search></el-search>
</div>

<hr>

<div id="app2">
    <el-button></el-button>
    <!-- <el-search></el-search> 错误的 -->
</div>

<script src="./libs/vue@2.7.16/vue.js"></script>
<script>
    // 组件:功能 (相当于vue实例)
    // 组件是可复用的 Vue 实例

    // 步骤:
    // 1. 定义组件
    // 2. 注册组件
    // 3. 使用组件

    // 一) 全局组件
    // 1. 定义按钮组件 (template选项在vue2版本中必须有根节点)
    const ElButton = {
        // 设置数据
        data() {
           return {
              message: "这是一个按钮123"
           }
        },
        // 渲染模板
        template: `
            <div>
                <div>{{message}}</div>
               <button @click="foo" style="padding: 10px 20px; border: 0; background-color: skyblue; color: white;">
                  点击按钮
                </button>   
            </div>
        `,
        // 设置方法
        methods: {
            // 提示
            foo(){
                alert("您好,触发事件。。。")
            }
        }
    }
    // 2. 注册组件(此处表示全局注册)
    Vue.component("el-button",ElButton);

    //禁止控制台输出日志信息
    Vue.config.productionTip = false;
    // 创建vue实例
    new Vue({
        //挂载容器
        el: "#app",
        // 注册组件(此处表示局部注册)
        components: {
            // 此处注册组件名称采用驼峰命名“ElSearch”,在使用的时候需要改成 “el-search”
            // "el-search": {},
           "ElSearch": {
                data(){
                    return {

                    }
                },
                template: `
                    <div>
                        <input type="text" placeholder="请输入关键字" style="width: 90%;height: 40px;">    
                    </div>
                `
           },
        }
    })
    new Vue({
        //挂载容器
        el: "#app2",
    })
    
// 注册组件注意事项:
// 1) 采用驼峰命名法注册组件名称时“”ElSearch,使用组件时需要改用短横线“el-search”
// 2) 不能使用html文档内置的标签名称作为组件名称例如: div header footer nav 
// 3) 组件中的data一个函数,并且返回一个对象
// 4) template选项需要有根节点(在vue@2版本)
// 5) 组件的属性计算、侦听,过滤,生命周期的钩子和vue实例的写法一样
</script>

组件嵌套关系

<div id="app">
    <element-parent></element-parent>
    <!-- <element-child></element-child> 错误的 -->
</div>
<script src="./libs/vue@2.7.16/vue.js"></script>
<script>
    //禁止控制台输出日志信息
    Vue.config.productionTip = false;

    // 定义子组件
    const ElementChild = {
        template: `
            <div>
                <h3>子组件</h3>
            </div>
        `
    }
    // 定义父组件
    const ElementParent = {
        template: `
            <div>
                <h2>父组件</h2>
                <element-child></element-child>
            </div>
        `,
        // 在父组件中注册子组件
        components: {
            ElementChild
        }
    }


    // vue实例对象
    new Vue({
        //挂载容器
        el: "#app",
        // 在vue实例中注册父组件
        components: {
            ElementParent
        }
    })

父组件传值给子组件

<div id="app">
    <parent></parent>
</div>
<script src="../libs/vue@2.7.16/vue.js"></script>
<script>
    // 父传子
    // 子组件
    const child = {
        // 自定义属性
        props: ["num"],
        template: `
            <div style="border: 1px solid #ccc">
                <h4>子组件</h4>
                <p>{{num}}</p>
            </div>
        `
    }

    // 父组件
    const parent = {
        // 在父组件中注册子组件
        components: {
            // child: child, 
            child
        },
        template: `
        <div style="border: 1px solid #000">
            <h3>父组件</h3>
            <child :num="100"></child>
        </div>
        
        `
    }

    //禁止控制台输出日志信息
    Vue.config.productionTip = false;
    new Vue({
        //挂载容器
        el: "#app",
        // 在vue实例中注册父组件
        components: {
            parent
        }
    })
</script>

子组件传值给父组件

<div id="app">
    <parent></parent>
</div>
<script src="../libs/vue@2.7.16/vue.js"></script>
<script>


    // 父传子
    // 子组件
    // (通常需要借助事件(延迟函数、钩子函数)发送数据)
    //  <button @click="send">点击发送</button>
    const child = {
        template: `
            <div style="border: 1px solid #ccc">
                <h4>子组件</h4>
               
            </div>
        `,
        methods: {
            send(){
                this.$emit("xxx",100)
            }
        },
        // 钩子函数
        created(){
            this.$emit("xxx",100)
        }
    }

    // 父组件
    const parent = {
        // 在父组件中注册子组件
        components: {
            // child: child, 
            child
        },
        template: `
        <div style="border: 1px solid #000">
            <h3>父组件</h3>
            <p>{{num}}</p>
            <child @xxx="recive"></child>
        </div>
        
        `,
        methods: {
            recive(cnum){
                this.num = cnum;
            }
        },
        data(){
            return {
                num: 0
            }
        }
    }

    //禁止控制台输出日志信息
    Vue.config.productionTip = false;
    new Vue({
        //挂载容器
        el: "#app",
        // 在vue实例中注册父组件
        components: {
            parent
        }
    })
</script>

兄弟组件之间传值

1)

<div id="app">
   <comp-a></comp-a>
   <comp-b></comp-b>
</div>
<script src="../libs/vue@2.7.16/vue.js"></script>
<script>
    // 创建vue实例作为通信的桥梁(这种有响应式)
    const bridge = new Vue();
    // 并列关系组件
    const CompA = {
        template: `
        <div>
            <h3>组件A</h3>
            <button @click="senda">数字自增</button>
        </div>
        `,
        data(){
            return {
                num: 100
            }
        },
        methods: {
             senda(){
                this.num ++;
                let value = this.num;
                bridge.$emit('xxx', value)
             },
        },
        created(){
            // 发送数据
            setTimeout(()=>{
                this.senda();
            },0)
        }
    }
    const CompB = {
        template: `
            <div>
                <h3>组件B</h3>
                <p>{{num}}</p>
            </div>

        `,
        data(){
            return {
                num: 0
            }
        },
        created(){
            // 监听组件A的事件且接收组件A的数据
            bridge.$on("xxx",(value)=>{
                this.num = value;
            })
        }
    }
    //禁止控制台输出日志信息
    Vue.config.productionTip = false;
    new Vue({
        //挂载容器
        el: "#app",
        components: { CompA , CompB },
    })
</script>

2)

<div id="app">
    <button @click="changeNum">点击按钮</button>
    <comp-header></comp-header>
    <comp-footer></comp-footer>
   
</div>
<script src="../libs/vue@2.7.16/vue.js"></script>
<script>


// 找到Vue的原型对象
// 在原型对象上添加的属性和方法,可以给所属构造函数的实例对象使用!!!
// 在原型对象上添加的数据,是没有响应式的。
Vue.prototype.num = 100;

// 定义组件
// 头部组件
const CompHeader = {
    template: `
    <header>
        <h3>头部组件</h3>
        <p>{{num}}</p>
    </header>
    `
}
// 尾部组件
const CompFooter = {
    template: `
    <footer>
        <h3>尾部组件</h3>
        <p>{{num}}</p>
    </footer>
    `
}


//禁止控制台输出日志信息
Vue.config.productionTip = false;
new Vue({
    //挂载容器
    el: "#app",
    // 注册组件
    components: {
        CompHeader, 
        CompFooter
    },
    // 改变num
    methods: {
        changeNum(){
            this.num ++
            console.log(this.num);
        }
    }
})

5.8) 混入语法

<div id="app">
    <h2>Vue实例</h2>
    <p>{{num}}</p>
    <button @click="add">按钮</button>

    <hr>
    <comp-a></comp-a>
    <hr>
    <comp-b></comp-b>      
    <hr>
    <comp-c></comp-c> 
</div>
<script src="./libs/vue@2.7.16/vue.js"></script>
<script>
    // 混入: 是指代码的重复使用
    // 提取重复的代码( vue实例optins选项 )
    const options = {
        data(){
            return {
                num: 100
            }
        },
        methods: {
            add(){
                this.num ++;
            }
        },
        watch: {
            num(nValue){
                console.log("值:",nValue);
            }
        },
        created(){
            console.log("初始化...")
        }
    }
    

    // 组件A
    const CompA = {
        // 当data选项中的数据和mixins选项中的属性和方法相同的情况,优先使用的是组件的属性和方法等
        data(){
            return {
                num: 1
            }
        },
        // 混入语法
        mixins: [
            options
        ],
        template: `
        <div>
            <h3>组件A</h3>
            <p>{{num}}</p>
            <button @click="add">按钮</button>
        </div>
        `,
        // data(){
        //     return {
        //         num: 100
        //     }
        // },
        // metods: {
        //     add(){
        //         this.num ++;
        //     }
        // }
    }
    // 组件B
    const CompB = {
        // 混入语法
        mixins: [
            options
        ],
        template: `
            <div>
                <h3>组件B</h3>
                <p>{{num}}</p>
                <button @click="add">按钮</button>
            </div>
        `,
        // data(){
        //     return {
        //         num: 100
        //     }
        // },
        // metods: {
        //     add(){
        //         this.num ++;
        //     }
        // }
    }
    // 组件C(也是定义组件的意思)
    const CompC = Vue.extend({
        // 混入语法
        mixins: [
            options
        ],
        template: `
            <div>
                <h3>组件C</h3>
                <p>{{num}}</p>
                <button @click="add">按钮</button>
            </div>
        `,
    })

    //禁止控制台输出日志信息
    Vue.config.productionTip = false;
    new Vue({
        // 混入语法
        mixins: [
            options
        ],
        //挂载容器
        el: "#app",
        // 注册组件
        components: { CompA , CompB , CompC},


    })
</script>

5.9) 组件插槽、动态组件

插槽: 是组件的拓展。让组件内容更加丰富、更加灵活渲染。

匿名插槽

<div id="app">
    <comp-header><span>搜狐  </span></comp-header>
    <comp-header><span>淘宝  </span></comp-header>
    <comp-header><span>京东  </span></comp-header>
    <comp-header><span>拼多多</span></comp-header>
</div>
<script src="./libs/vue@2.7.16/vue.js"></script>
<script>

    // 匿名插槽
    // <slot></slot>
    // 编写头部组件
    const CompHeader = {
        template: `
            <header class="header">
                <!-- 插槽 -->
                <div class="left">
                    <slot></slot>
                </div>
            </header>
        `
    }
    //禁止控制台输出日志信息
    Vue.config.productionTip = false;
    new Vue({
        //挂载容器
        el: "#app",
        // 注册组件
        components: {CompHeader}
    })
</script>

具名插槽

<div id="app">
    <comp-header>
        <!-- 代表left插槽 -->
        <template v-slot:left>
             <span>LOGO</span>
        </template>

        <!-- 代表center插槽 -->
        <template v-slot:center>
            <input type="text" placeholder="请输入关键字">
        </template>

         <!-- 代表right插槽 -->
         <template #right>
           <a href="#">登录</a>
        </template>
    </comp-header>

</div>
<script src="./libs/vue@2.7.16/vue.js"></script>
<script>
    // 具名插槽
    // <slot name="left"></slot>
    // 编写头部组件
    const CompHeader = {
        template: `
            <header class="header">
                <!-- 插槽 -->
                <div class="left">
                    <slot name="left"></slot>
                </div>
                <div class="center">
                    <slot name="center"></slot>
                </div>
                <div class="right">
                    <slot name="right"></slot>
                </div>
            </header>
        `
    }
    //禁止控制台输出日志信息
    Vue.config.productionTip = false;
    new Vue({
        //挂载容器
        el: "#app",
        // 注册组件
        components: {CompHeader}
    })
</script>

动态组件: 可以利用内置组件component的is属性,决定渲染哪一个组件。

<div id="app">
  <!-- <new-song></new-song> -->
  <!-- <hot-song></hot-song> -->

  <!-- tab选项卡 -->
  <div class="tab">
     <div @click="tabFunc(0)" :class="['btn',index==0?'active':'']">最新</div>
     <div @click="tabFunc(1)" :class="['btn',index==1?'active':'']">热门</div>
  </div>

  <!-- 内置组件 -->
  <component :is="compName"></component>
</div>
<script src="./libs/vue@2.7.16/vue.js"></script>
<script>

    // 定义组件
    // 最新音乐
    const NewSong = {
        template: `
        <div style="height: 120px;background-color: pink;">
            <h3>最新音乐</h3>
        </div>
        `
    }
     // 热门音乐
     const HotSong = {
        template: `
        <div style="height: 120px;background-color: yellowgreen;">
            <h3>热门音乐</h3>
        </div>
        `
    }

    //禁止控制台输出日志信息
    Vue.config.productionTip = false;
    new Vue({
        // 设置数据
        data(){
            return {
                // 记录组件名称
                compName: 'new-song',
                index: 0
            }
        },
        // 设置方法
        methods: {
            tabFunc(i){
                this.index = i;
                // i === 0 ? this.compName = "new-song": this.compName = "hot-song";
                if(i === 0) this.compName = "new-song";
                if(i === 1) this.compName = "hot-song";
            }
        },
        //挂载容器
        el: "#app",
        // 注册组件
        components: {
            NewSong,
            HotSong
        }
    })
</script>

5.10) 过渡、动画

利用内置组件 transition 组件,可以实现过渡、动画这些效果。

可以看见元素/组件

从显示到隐藏或从隐藏到显示的这个过程。

显示: 入场效果

隐藏: 离场效果

过渡案例:

<style>
    /* 入场类名 */
    /* 入场之前的样式 */
    .v-enter {
        transform: translateX(-100%);
        opacity: 0;
    }
    /* 入场过程中的样式 */
    .v-enter-active {
        transition: all .5s;
    }
    .v-enter-to {
        transform: translateX(0px);
        opacity: 1;
    }


    /* 离场类名 */
    /* 离场之前的样式 */
    .v-leave {
        transform: translateY(0px);
        opacity: 1;
    }
    /* 离场过程中的样式 */
    .v-leave-active {
        transition: all .5s;
    }
    /* 离场后的样式 */
    .v-leave-to {
        transform: translateY(-100%);
        opacity: 0;
    }


    /* 设置transition组件的name属性为demo后 */
     /* 入场类名 */
    /* 入场之前的样式 */
    .demo-enter {
        transform: translateX(-100%) rotate(180deg);
        opacity: 0;
    }
    /* 入场过程中的样式 */
    .demo-enter-active {
        transition: all .5s;
    }
    .demo-enter-to {
        transform: translateX(0px)  rotate(0deg);
        opacity: 1;
    }


    /* 离场类名 */
    /* 离场之前的样式 */
    .demo-leave {
        transform: translateY(0px)  rotate(0deg);
        opacity: 1;
    }
    /* 离场过程中的样式 */
    .demo-leave-active {
        transition: all .5s;
    }
    /* 离场后的样式 */
    .demo-leave-to {
        transform: translateY(-100%) rotate(180deg);
        opacity: 0;
    }
</style>
</head>

<body>
<div id="app">
    <div class="container mt-2">
        <div class="btn btn-success" @click="isShow=true">入场(显示)</div>
        <div class="btn btn-danger" @click="isShow=false">离场(隐藏)</div>

        <!-- <div v-if="isShow" class="bg-primary mt-2" style="height: 200px;"></div> -->


        <transition>
            <div v-if="isShow" class="bg-primary mt-2" style="height: 200px;"></div>
        </transition>

        <transition name="demo">
            <div v-if="isShow" class="bg-primary mt-2" style="height: 200px;"></div>
        </transition>
    </div>
    

</div>
<script src="./libs/vue@2.7.16/vue.js"></script>
<script>


    //禁止控制台输出日志信息
    Vue.config.productionTip = false;
    new Vue({
        //挂载容器
        el: "#app",
        // 数据
        data(){
            return {
                isShow: true 
            }
        },


    })
</script>

动画案例:

<!-- 动画库 -->
<link rel="stylesheet" href="./libs/animate.min.css">
<style>
    /* 入场类名 */
    .enter-box {
        animation: enter-ani .5s  forwards;
    }

    /* 离场类名 */
    .leave-box {
        animation: leave-ani .5s  forwards;
    }
    

    /* 自定义动画 */
    /* 入场动画 */
    @keyframes enter-ani {
        0% {
            transform: scale(.5) rotate(180deg);
            opacity: 0;
        }
        100% {
            transform: scale(1) rotate(0deg);
            opacity: 1;
        }
    }
    /* 离场动画 */
    @keyframes leave-ani {
        0% {
            transform: scale(1) rotate(0deg);
            opacity: 1;
        }
        100% {
            transform: scale(.5) rotate(180deg);
            opacity: 0;
        }
    }
</style>
</head>

<body>
<div id="app">
    <div class="container mt-2">
        <div class="btn btn-success" @click="isShow=true">入场(显示)</div>
        <div class="btn btn-danger" @click="isShow=false">离场(隐藏)</div>

        <!-- 处理动画,利用enter-active,leave-active这些属性设置 -->
        <!-- 1) 自定义动画 -->
        <transition
            enter-active-class="enter-box"
            leave-active-class="leave-box"
            >
            <div v-if="isShow" class="bg-primary mt-2" style="height: 200px;"></div>
        </transition>


        <!-- 2) 使用动画库 -->
        <transition
            enter-active-class="animate__animated  animate__backInLeft"
            leave-active-class="animate__animated  animate__backOutDown"
            >
            <div v-if="isShow" class="bg-warning mt-2" style="height: 200px;"></div>
        </transition>
    </div>
    

</div>
<script src="./libs/vue@2.7.16/vue.js"></script>
<script>
    //禁止控制台输出日志信息
    Vue.config.productionTip = false;
    new Vue({
        //挂载容器
        el: "#app",
        // 数据
        data(){
            return {
                isShow: true 
            }
        },
    })
</script>

keep-alive组件缓存组件状态

<div id="app">
    <div class="container mt-2">
        <div class="btn btn-success" @click="isShow=true">入场(显示)</div>
        <div class="btn btn-danger" @click="isShow=false">离场(隐藏)</div>

        <!-- 处理动画,利用enter-active,leave-active这些属性设置 -->
        <!-- 1) 自定义动画 -->
        <transition
            enter-active-class="enter-box"
            leave-active-class="leave-box"
            >
           <!-- 组件 -->
           <!-- vue实例和组件都有生命周期 创建  挂载  更新  销毁 -->
           <!-- keep-alive 缓存数据状态的内置组件 -->
           <!-- include (包括) 和 exclude (排除) 允许组件有条件地缓存。二者都可以用逗号分隔字符串、正则表达式或一个数组来表示: -->
           <keep-alive>
                <aaa v-if="isShow"></aaa>
           </keep-alive>
          
        </transition>
    </div>
    

</div>
<script src="./libs/vue@2.7.16/vue.js"></script>
<script>



    // 定义组件
    const aaa = {
        data(){
            return {
                inpText: ""
            }
        },
        methods: {
            getInputText(){
                console.log("输入的值:",this.inpText)
            }
        },
        template: `
            <div class="bg-info mt-2 p-3" style="height: 200px;">
                <input v-model="inpText" type="text" class="form-control" placeholder="请输入关键字">
                <button @click="getInputText" class="btn btn-primary mt-2">确定</button>
            </div>
        `,
        created(){
            console.log("创建了")
        },
        destroyed(){
            console.log("销毁了")
        }
    }

    //禁止控制台输出日志信息
    Vue.config.productionTip = false;
    new Vue({
        //挂载容器
        el: "#app",
        // 数据
        data(){
            return {
                isShow: true 
            }
        },
        // 注册组件
        components: {
            aaa
        }
    })
</script>

组件:

1) 自定义组件(定义组件、注册组件、使用组件)

2) 内置组件 (transition 、component 、keep-alive)

5.11)脚手架(另外一博客)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

杨桃贝贝

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

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

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

打赏作者

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

抵扣说明:

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

余额充值