3、Vue 笔记(axios、Vue 动画、Vue 组件、使用 this.$refs 来获取元素和组件、Vue 组件中 data 和 props 的区别)

文章目录

    • axios 的使用
      • 1、axios 基本使用
      • 2、vue 中的 axios
    • Vue中的动画
      • 1、使用过渡类名实现动画
      • 2、可修改 v- 前缀
      • 3、使用第三方类库实现动画
      • 4、使用钩子函数实现小球的半场动画
      • 5、列表动画
    • Vue 组件
      • 定义 Vue 组件
      • 全局组件定义的三种方式
        • 第一种方式:
        • 第二种方式:
        • 第三种方式:
      • 私有组件定义
      • 组件中展示数据和响应事件
      • 组件切换
        • 切换方式一(使用flag标识符结合v-if和v-else切换组件)
        • 切换方式二(使用component标签的:is属性来切换组件,并添加动画)
      • 组件切换时切换动画
      • 父组件向子组件传值
      • 父组件向子组件传递方法
      • 组件案例-评论列表
    • 使用 `this.$refs` 来获取元素和组件
      • `ref` 介绍
      • `this.$refs` 介绍
      • 实例
    • 在 Vue 组件中 data 和 props 的区别
    • 补充(localStorage 本地存储)

axios 的使用

Axios 是一个基于 promise 网络请求库,作用于node.js和浏览器中,它是 isomorphic 的(即同一套代码可以运行在浏览器和 node.js 中)。在服务端它使用原生 node.js http 模块, 而在客户端(浏览端)则使用XMLHttpRequests。

1、axios 基本使用

axios 必须先导入才可以使用
使用 get 或 post 方法即可发送对应的请求
then 方法中的回调函数会在请求成功或失败时触发(成功是第一个,失败时第二个函数)
通过回调函数的形参可以获取响应内容,或错误信息

代码:

DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
head>

<body>
    <input type="button" value="get请求" class="get">
    <input type="button" value="post请求" class="post">
    
    <script src="https://unpkg.com/axios/dist/axios.min.js">script>
    <script>
        /*
            接口1:随机笑话
            请求地址:https://autumnfish.cn/api/joke/list
            请求方法:get
            请求参数:num(笑话条数,数字)
            响应内容:随机笑话
        */
        document.querySelector(".get").onclick = function () {
       
            axios.get("https://autumnfish.cn/api/joke/list?num=3")
                .then(function (response) {
       
                    console.log(response);
                }, function (err) {
       
                    console.log(err);
                })
        }
        /*
            接口2:用户注册
            请求地址:https://autumnfish.cn/api/user/reg
            请求方法:post
            请求参数:username(用户名,字符串)
            响应内容:注册成功或失败

        */
        document.querySelector(".post").onclick = function () {
       
            axios.post("https://autumnfish.cn/api/user/reg", {
        username: "jack" })
                .then(function (response) {
       
                    console.log(response);
                }, function (err) {
       
                    console.log(err);
                })
        }

    script>
body>

html>

2、vue 中的 axios

代码:

DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
head>

<body>
    <div id="app">
        <input type="button" value="获取笑话" @click="getJoke">
        <p>{
    {joke}}p>
    div>
    
    <script src="https://unpkg.com/axios/dist/axios.min.js">script>
    <script src=" https://cdn.staticfile.org/vue/2.2.2/vue.min.js">script>
    <script>
        /*
            接口1:随机笑话
            请求地址:https://autumnfish.cn/api/joke
            请求方法:get
            请求参数:无
            响应内容:随机笑话
        */
        var app = new Vue({
       
            el: "#app",
            data: {
       
                joke: "joke"
            },
            methods: {
       
                getJoke: function () {
       
                    console.log(this);
                    var that = this;
                    axios.get("https://autumnfish.cn/api/joke").then(
                        function (response) {
       
                            // console.log(response);
                            console.log(response.data);
                            that.joke = response.data;
                        }, function (err) {
       
                            console.log(err);
                        }
                    )
                }
            },
        })

    script>
body>

html>
axios 回调函数中的 this 已经改变,无法访问到 data 中数据
把 this 保存起来,回调函数中直接使用保存的 this 即可
和本地应用的最大区别就是改变了数据来源

Vue中的动画

链接:Vue 动画

为什么要有动画:动画能够提高用户的体验,帮助用户更好的理解页面中的功能;

1、使用过渡类名实现动画

代码:

DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Documenttitle>
    
    <style>
        /* v-enter [这是一个时间点] 是进入之前,元素的起始状态,此时还没有开始进入 */
        /* v-leave-to [这是一个时间点] 是动画离开之后,离开的终止状态,此时,元素动画已经结束了 */
        .v-enter,
        .v-leave-to {
       
            opacity: 0;
            transform: translateX(150px);
        }

        /* v-enter-active 【入场动画的时间段】 */
        /* v-leave-active 【离场动画的时间段】 */
        .v-enter-active,
        .v-leave-active {
       
            transition: all 0.8s ease;
        }
    style>
head>

<body>
    <div id="app">
        <input type="button" value="toggle" @click="flag=!flag">
        
        
        
        <transition>
            <h3 v-if="flag">这是一个H3h3>
        transition>

    div>

    
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
    <script>
        var vm = new Vue({
       
            el: '#app',
            data: {
       
                flag: false
            },
            methods: {
       }
        });
    script>
body>

html>

2、可修改 v- 前缀

DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Documenttitle>
    
    <style>
        /* v-enter [这是一个时间点] 是进入之前,元素的起始状态,此时还没有开始进入 */
        /* v-leave-to [这是一个时间点] 是动画离开之后,离开的终止状态,此时,元素动画已经结束了 */
        .v-enter,
        .v-leave-to {
       
            opacity: 0;
            transform: translateX(150px);
        }

        /* v-enter-active 【入场动画的时间段】 */
        /* v-leave-active 【离场动画的时间段】 */
        .v-enter-active,
        .v-leave-active {
       
            transition: all 0.8s ease;
        }



        .my-enter,
        .my-leave-to {
       
            opacity: 0;
            transform: translateY(70px);
        }

        .my-enter-active,
        .my-leave-active {
       
            transition: all 0.8s ease;
        }
    style>
head>

<body>
    <div id="app">
        <input type="button" value="toggle" @click="flag=!flag">
        
        
        
        <transition>
            <h3 v-if="flag">这是一个H3h3>
        transition>


        <hr>
        <input type="button" value="toggle2" @click="flag2=!flag2">
        <transition name="my">
            <h6 v-if="flag2">这是一个H6h6>
        transition>

    div>

    
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
    <script>
        var vm = new Vue({
       
            el: '#app',
            data: {
       
                flag: false,
                flag2: false
            },
            methods: {
       }
        });
    script>
body>

html>

3、使用第三方类库实现动画

1)导入动画类库:

"stylesheet" type="text/css" href="./lib/animate.css">

2)定义 transition 及属性:

        <transition 
         enter-active-class="bounceIn" 
         leave-active-class="bounceOut" 
         :duration="{enter: 200, leave: 400}">
            <h3 v-if="flag" class="animated">这是一个H3h3>
        transition>

代码:

DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Documenttitle>
    
    <link rel="stylesheet" href="https://unpkg.com/animate.css@3.5.2/animate.min.css">
    
head>

<body>
    <div id="app">
        <input type="button" value="toggle" @click="flag=!flag">
        
        
        <transition enter-active-class="bounceIn" leave-active-class="bounceOut" :duration="{enter: 200, leave: 400}">
            <h3 v-if="flag" class="animated">这是一个H3h3>
        transition>

    div>

    
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
    <script>
        var vm = new Vue({
       
            el: '#app',
            data: {
       
                flag: false
            },
            methods: {
       }
        });
    script>
body>

html>

4、使用钩子函数实现小球的半场动画

代码:

DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Documenttitle>
    <style>
        .ball {
       
            width: 15px;
            height: 15px;
            border-radius: 50%;
            background-color: red;
        }
    style>
head>

<body>
    <div id="app">
        <input type="button" value="快到碗里来" @click="flag=!flag">
        
        
        <transition @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter">
            <div class="ball" v-show="flag">div>
        transition>

    div>

    
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
    <script>
        var vm = new Vue({
       
            el: '#app',
            data: {
       
                flag: false
            },
            methods: {
       
            	// 定义三个 methods 钩子方法:
                // 注意: 动画钩子函数的第一个参数: el ,表示 要执行动画的那个 DOM 元素 是原生的JS DOM对象
                // 大家可以认为 , el 是通过 document.getElementById('') 方式获取到的原生JS DOM 对象
                beforeEnter(el) {
       
                    // beforeEnter 表示动画入场之前,此时,动画尚未开始,可以在 beforeEnter 中,设置元素开始动画之前的起始样式
                    // 设置小球开始动画之前的,起始位置
                    el.style.transform = "translate(0,0)"
                },
                enter(el, done) {
       
                    // 这句话,没有实际的作用,但是,如果不写,出不来动画效果
                    // 可以认为 el.offsetWidth 会强制动画刷新
                    el.offsetWidth
                    // enter 表示动画 开始之后的样式,这里,可以设置小球完成动画之后的 结束状态
                    el.style.transform = "translate(150px,450px)"
                    el.style.transition = "all 1s ease"

                    // 这里的done,其实就是afterEnter 这个函数,也就是说:done 是 afterEnter 函数的引用
                    done()
                },
                afterEnter(el) {
       
                    // 动画完成之后,会调用 afterEnter 
                    this.flag = !this.flag
                }
            }
        });
    script>
body>

html>

5、列表动画

代码:

DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Documenttitle>
    <style>
        li {
       
            border: 1px dashed #999;
            margin: 5px;
            line-height: 35px;
            padding-left: 5px;
            font-size: 12px;
            width: 100%;
        }

        li:hover {
       
            background-color: pink;
            transition: all 0.6s ease;
        }


        .v-enter,
        .v-leave-to {
       
            opacity: 0;
            transform: translateY(80px);
        }

        .v-enter-active,
        .v-leave-active {
       
            transition: all 0.6s ease;
        }

        /* 下面的 .v-move 和 .v-leave-active 配合使用,能够实现列表后续元素,渐渐地飘上来的效果 */
        .v-move {
       
            transition: all 0.6s ease;
        }

        .v-leave-active {
       
            position: absolute;
        }
    style>
head>

<body>
    <div id="app">

        <div>
            <label for="">
                Id:
                <input type="text" v-model="id">
            label>

            <label for="">
                Name:
                <input type="text" v-model="name">
            label>

            <input type="button" value="增加" @click="add">

        div>

        
        
        
        
        
        <transition-group appear tag="ul">
            <li v-for="(item,i) in list" :key="item.id" @click="del(i)">
                {
    {item.id}} --- {
    {item.name}}
            li>
        transition-group>

        

    div>

    
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
    <script>
        var vm = new Vue({
       
            el: '#app',
            data: {
       
                id: '',
                name: '',
                list: [
                    {
        id: 1, name: '周哥' },
                    {
        id: 2, name: '李哥' },
                    {
        id: 3, name: '张哥' },
                    {
        id: 4, name: '沈哥' }
                ]
            },
            methods: {
       
                add() {
       
                    this.list.push({
        id: this.id, name: this.name })
                    this.id = this.name = ''
                },
                del(i) {
       
                    this.list.splice(i, 1)
                }
            }
        });
    script>
body>

html>

Vue 组件

定义 Vue 组件

  • 什么是模块化:模块化是从代码的角度出发,分析项目,把项目中一些功能类似的代码,单独的抽离为一个个的模块;那么为了保证大家以相同的方式去封装模块,于是我们就创造了模块化的规范(CommonJS规范);
    • 模块化的好处:方便项目的开发;和后期的维护与扩展;今后如果需要某些固定功能的模块,则直接拿来引用就行,提高了项目开发效率!
  • 什么是组件化:从UI的角度出发考虑问题,把页面上有重用性的UI解构和样式,单独的抽离出来,封装为单独的组件;
    • 组件化的好处:随着项目规模的发展,我们手里的组件,会越来越多,这样,我们今后一个页面中的UI,几乎都可以从手中拿现成的组件拼接出来;方便项目的开发和维护;

全局组件定义的三种方式

第一种方式:

1、先调用 Vue.extend() 得到组件的构造函数:

// 创建全局组件的第一种方式:   component
 const com1 = Vue.extend({
     
   template: '

这是创建的第一个全局组件

'
// template 属性,表示这个组件的 UI 代码解构 })

2、通过 Vue.component(‘组件的名称’, 组件的构造函数) 来注册全局组件:

 // 使用 Vue.component 向全局注册一个组件
 // Vue.component('组件的名称', 组件的构造函数)
 Vue.component('mycom1', com1)

注意:

如果使用 Vue.component 定义全局组件的时候,组件名称使用了驼峰命名,则在引用组件的时候,需要把大写的驼峰改为小写的字母同时,两个单词之间,使用 - 链接
如果不使用驼峰,则直接拿名称来使用即可

以上两步可写为一步:

Vue.component('myCom1', Vue.extend({
     
    template: '

这是使用 Vue.extend 创建的组件

'
}))

3、把注册好的全局组件名称,以标签形式引入到页面中即可:


 <mycom1>mycom1>

第二种方式:

直接使用 Vue.component(‘组件名称’, { 组件模板对象 })

const com2Obj = {
     
   // 1. template 属性中,不能单独放一段文本,必须用标签包裹起来;
   // 2. 如果在 template 属性中,想要放多个元素了,那么,在这些元素外,必须有唯一的一个根元素进行包裹;
   template: '

这是直接使用 Vue.component 创建出来的组件

红红火火

'
} // 定义全局的组件 // Vue.component 的第二个参数,既接收 一个 组件的构造函数, 同时,也接受 一个对象 Vue.component('mycom2', com2Obj)

或者:

Vue.component('mycom2', {
     
    // 注意: 不论是哪种方式创建出来的组件,组件的 template 属性指向的模板内容,必须有且只能有唯一的一个根元素
    template: '

这是直接使用 Vue.component 创建出来的组件的组件

123
'
})

第三种方式:

1、先使用 template 标签定义一个模板的代码解构:



<template id="tmpl">
 <div>
   <h3>哈哈,这是在外界定义的组件UI解构h3>
   <h3>我是来捣乱的h3>
 div>
template>

2、使用 Vue.component 注册组件:

 // 这是定义的全局组件
 Vue.component('mycom3', {
     
   template: '#tmpl'
 })

注意: 从更抽象的角度来说,每个组件,就相当于是一个自定义的元素; 注意: 组件中的DOM结构,有且只能有唯一的根元素(Root Element)来进行包裹!

私有组件定义

私有组件只能当前定义的 VM 实例中可以使用

代码:

DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Documenttitle>
head>

<body>
    <div id="app">
        <login>login>
    div>

    <template id="tmpl2">
        <div>
            <h1>这是私有的 login 组件h1>
        div>
    template>

    
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
    <script>
        var vm = new Vue({
       
            el: '#app',
            data: {
       },
            methods: {
       },
            components: {
        //定义实例内部私有组件
                login: {
       
                    template: "#tmpl2"
                }
            }
        });
    script>
body>

html>

组件中展示数据和响应事件

1.组件可以有自己的 data 数据
2.组件的 data 和实例的 data 有点不一样,实例中的 data 可以为一个对象,但是组件中的 data 必须是一个方法
3.组件中的 data 除了必须为一个方法之外,这个方法内部,还必须返回一个对象才行
4.组件中的 data 数据使用方式,和实例中的 data 使用方式完全一样!!!

   Vue.component('mycom1', {
     
       template: "

这是全局组件 --- { { msg }}

"
, data: function () { return { msg: '这是组件中的data定义的数据' } } })

计数器案例:

DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Documenttitle>
head>

<body>
    <div id="app">
        <counter>counter>
        <hr>
        <counter>counter>
        <hr>
        <counter>counter>
    div>

    <template id="tmpl">
        <div>
            <input type="button" value="+1" @click="increment">
            <h3>{
    { count }}h3>
        div>
    template>

    
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
    <script>
        var dataObj = {
        count: 0 }
        // 这是一个计数器组件,身上有个按钮,每当点击按钮,让 data 中的 count 值 +1
        Vue.component('counter', {
       
            template: '#tmpl',
            data: function () {
       
                // return dataObj
                return {
        count: 0 }
            },
            methods: {
       
                increment() {
       
                    this.count++
                }
            }
        })

        var vm = new Vue({
       
            el: '#app',
            data: {
       },
            methods: {
       }
        });
    script>
body>

html>

以上案例可以解释为什么 组件中的 data 必须是一个方法 以及 组件中的 data 除了必须为一个方法之外,这个方法内部,还必须返回一个对象才行

“组件中的data写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的data,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。而单纯的写成对象形式,就使得所有组件实例共用了一份data,就会造成一个变了全都会变的结果。”

组件切换

切换方式一(使用flag标识符结合v-if和v-else切换组件)

代码:

DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Documenttitle>
head>

<body>
    <div id="app">
        <a href="" @click.prevent="flag=true">登录a>
        <a href="" @click.prevent="flag=flase">注册a>

        <login v-if="flag">login>
        <register v-else="flag">register>
    div>

    
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
    <script>
        Vue.component('login', {
       
            template: '

登录组件

'
}) Vue.component('register', { template: '

注册组件

'
}) var vm = new Vue({ el: '#app', data: { flag: true }, methods: { } });
script> body> html>

切换方式二(使用component标签的:is属性来切换组件,并添加动画)

代码:

DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Documenttitle>
head>

<body>
    <div id="app">
        <a href="" @click.prevent="comName='login'">登录a>
        <a href="" @click.prevent="comName='register'">注册a>

        
        
        <component :is="comName">component>

    div>

    
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
    <script>
        // 组件名称是 字符串
        Vue.component('login', {
       
            template: '

登录组件

'
}) Vue.component('register', { template: '

注册组件

'
}) var vm = new Vue({ el: '#app', data: { comName: 'login' //当前 component 中的 :is 绑定的组件名称 }, methods: { } });
script> body> html>

组件切换时切换动画

代码:

DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Documenttitle>
    <style>
        .v-enter,
        .v-leave-to {
       
            opacity: 0;
            transform: translateX(150px);
        }

        .v-enter-active,
        .v-leave-active {
       
            transition: all 0.5s ease;
        }
    style>
head>

<body>
    <div id="app">
        <a href="" @click.prevent="comName='login'">登录a>
        <a href="" @click.prevent="comName='register'">注册a>

        
        <transition mode='out-in'>
            <component :is="comName">component>
        transition>

    div>

    
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
    <script>
        // 组件名称是 字符串
        Vue.component('login', {
       
            template: '

登录组件

'
}) Vue.component('register', { template: '

注册组件

'
}) var vm = new Vue({ el: '#app', data: { comName: 'login' //当前 component 中的 :is 绑定的组件名称 }, methods: { } });
script> body> html>

注意:通过 mode 属性,设置组件切换时候的模式 非常重要,可以使动画看起来非常流畅。

父组件向子组件传值

步骤:
1、把要传递给子组件的数据,作为 自定义属性,通过 v-bind: 绑定到子组件身上
2、在子组件中,不能直接使用父组件传递过来的数据,需要先使用 props 数组来接收一下
3、注意:在接收父组件传递过来的 props 的时候,接收的名称,一定要和父组件传递过来的自定义属性,名称保持一致!
代码:

DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Documenttitle>
head>

<body>
    <div id="app">
        
        <com1 v-bind:parentmsg="msg">com1>
    div>

    
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
    <script>
        var vm = new Vue({
       
            el: '#app',
            data: {
       
                msg: '123 父组件中的数据'
            },
            methods: {
       },
            components: {
       

                // 结论: 经过演示,发现,子组件中,默认无法访问到 父组件中的data 上的数据 和methods 中的方法
                com1: {
       
                    data() {
         //注意: 子组件中的data数据,并不是通过 父组件传递过来的,而是子组件自身私有的,
                        // 比如:子组件通过Ajax,请求回来的数据,都可以放到 data 身上
                        // data 上的数据,都是可读可写的
                        return {
       
                            title: '123',
                            content: 'qqq'
                        }
                    },
                    template: '

这是子组件 --- { { parentmsg }}

'
, // 注意: 组件中的 所有 props 中的数据,都是通过 父组件传递给 子组件的 // props 中的数据,都是只读的,无法重新赋值 props: ['parentmsg'], //把父组件传递过来的parentmsg 属性,现在props 数组中定义一下,这样才能使用这个数据 directives: { }, filters: { }, components: { }, methods: { changed() { this.parentmsg = '被修改了' } }, } } });
script> body> html>

父组件向子组件传递方法

组件向子组件 传递方法,使用的是 事件绑定机制,v-on,当我们自定义了 一个 事件属性之后,那么,子组件就能够,通过某些方式,来调用 传递进去的这个方法了
代码:

DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Documenttitle>
head>

<body>
    <div id="app">
        
        <com2 v-on:func="show">com2>
    div>

    <template id="tmpl">
        <div>
            <h1>这是 子组件h1>
            <input type="button" value="这是子组件中的按钮 - 点击它,触发 父组件传递过来的 func 方法" @click="myclick">
        div>
    template>

    
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
    <script>

        // 定义了一个字面量类型的 组件模板对象
        var com2 = {
       
            template: '#tmpl',  //通过指定一个Id,表示说,要去加载 这个指定Id的 template 元素中的内容,当做组件的HTML结构
            data() {
       
                return {
       
                    sonmsg: {
        name: '小头儿子', age: 6 }
                }
            },
            methods: {
       
                myclick() {
       
                    // console.log('ok')
                    // 当点击 子组件 按钮的时候,如何拿到父组件 传递过来的 func 方法,并调用这个方法?
                    // emit 英文原意:是触发,调用,发射的意思
                    // this.$emit('func', 123, 456)
                    this.$emit('func', this.sonmsg)
                }
            },
        }

        var vm = new Vue({
       
            el: '#app',
            data: {
       
                datamsgFormSon: null
            },
            methods: {
       
                show(data) {
       
                    // console.log('调用了父组件身上的 show 方法: --- ' + data)
                    console.log(data)
                    this.datamsgFormSon = data
                }
            },
            components: {
       
                com2
            }
        });
    script>
body>

html>

更多组件之间的传值参考网站:子组件与父组件之间传值

组件案例-评论列表

分析:发表评论的业务逻辑
1.评论的数据存到哪里去??? 存放到 localStorage 中
2.先组织出一个最新的评论数据对象
3.想办法,把第二步中得到的评论对象,保存到 localStorage 中
3.1 localStorage 只支持存放字符串对象,要先调用 JSON.stringify
3.2 在保存最新的评论数据之前,要先从 localStorage 获取之前的评论数据( string ),转化为 一个 数组对象
然后,把最新的评论,push 到这个数组
3.3 如果获取到的 localStorage 中的 评论字符串,为空不存在,则 可以 返回一个 ‘[]’ 让 JSON.parse 去转换
3.4 把 最新的评论列表数组,再次调用 JSON.stringify 转为 数组字符串,然后调用 localStorage.setItem()

代码:

DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Documenttitle>
    <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
head>

<body>
    <div id="app">

        <cmt-box @func="loadComments">cmt-box>


        <ul class="list-group">
            <li class="list-group-item" v-for="item in list" :key="item.id">
                <span class="badge">评论人 : {
    { item.user }}span>
                {
    { item.content }}
            li>

        ul>

    div>

    <template id="tmpl">
        <div>
            <div class="form-group">
                <label>评论人:label>
                <input type="text" class="form-control" v-model="user">
            div>

            <div class="form-group">
                <label>评论内容:label>
                <textarea class="form-control" v-model="content">textarea>
            div>

            <div class="form-group">
                <input type="button" value="发表评论" class="btn btn-primary" @click="postComment">
            div>
        div>
    template>

    
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
    <script>

        var commentBox = {
       
            data() {
       
                return {
       
                    user: '',
                    content: ''
                }
            },
            template: '#tmpl',
            methods: {
       
                postComment() {
         //发表评论的方法
                    // 分析:发表评论的业务逻辑
                    // 1.评论的数据存到哪里去??? 存放到 localStorage 中
                    // 2.先组织出一个最新的评论数据对象
                    // 3.想办法,把第二步中得到的评论对象,保存到 localStorage 中
                    // 3.1 localStorage 只支持存放字符串对象,要先调用 JSON.stringify
                    // 3.2 在保存最新的评论数据之前,要先从 localStorage 获取之前的评论数据( string ),转化为 一个 数组对象
                    //     然后,把最新的评论,push 到这个数组
                    // 3.3 如果获取到的 localStorage 中的 评论字符串,为空不存在,则 可以 返回一个 '[]'  让 JSON.parse 去转换
                    // 3.4 把 最新的评论列表数组,再次调用 JSON.stringify 转为 数组字符串,然后调用 localStorage.setItem()

                    var comment = {
        id: Date.now(), user: this.user, content: this.content }

                    // 从 localStorage 中获取所有的评论
                    var list = JSON.parse(localStorage.getItem('cmts') || '[]')
                    list.unshift(comment)
                    // 重新保存最新的评论数据
                    localStorage.setItem('cmts', JSON.stringify(list))

                    this.user = this.content = ''
                    // 子组件调用父组件方法
                    this.$emit('func')
                }
            },
        }

        var vm = new Vue({
       
            el: '#app',
            data: {
       
                list: [
                    {
        id: Date.now(), user: '李白', content: '天生我材必有用' },
                    {
        id: Date.now(), user: '小李白', content: '劝君更尽一杯酒' },
                    {
        id: Date.now(), user: '小李', content: '小李飞刀' },
                ]
            },
            beforeCreate() {
         // 注意:这里不能调用 loadComments 方法,因为在执行这个钩子函数的时候,data 和 methods 都还没有被初始化好

            },
            created() {
       
                this.loadComments()
            },
            methods: {
       
                loadComments() {
         //从本地的localStorage 中,加载评论列表
                    var list = JSON.parse(localStorage.getItem('cmts') || '[]')
                    this.list = list

                }
            },
            components: {
       
                'cmt-box': commentBox
            }
        });
    script>
body>

html>

使用 this.$refs 来获取元素和组件

ref 介绍

ref 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。如果在普通的 DOM
元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向该子组件实例
通俗的讲,ref特性就是为元素或子组件赋予一个ID引用,通过 this.$refs.refName 来访问元素或子组件的实例

this.$refs 介绍

this.$refs 是一个对象,持有当前组件中注册过 ref 特性的所有 DOM 元素和子组件实例
注意: $refs只有在组件渲染完成后才填充,在初始渲染的时候不能访问它们,并且它是非响应式的,因此不能用它在模板中做数据绑定

实例

DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Documenttitle>
head>

<body>
    <div id="app">
        <input type="button" value="获取元素" @click="getElement" ref="mtbtn">

        <h3 id="myh3" ref="myh3">哈哈哈,今天天气真好!h3>

        <hr>

        <login ref="mylogin">login>
    div>

    
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
    <script>
        var login = {
       
            template: '

登录组件

'
, data() { return { msg: 'son msg' } }, methods: { show() { console.log('调用了子组件方法') } }, } var vm = new Vue({ el: '#app', data: { }, methods: { getElement() { // console.log(document.getElementById('myh3').innerText) // ref 是英文单词 【reference】 值类型 和 引用类型 referenceError // console.log(this.$refs.myh3.innerText) // console.log(this.$refs.mylogin.msg) this.$refs.mylogin.show() } }, components: { login } });
script> body> html>

在 Vue 组件中 data 和 props 的区别

  1. data 在组件中,要被定义成 function 并返回一个对象
  2. props 在组件中,要被定义成数组,其中,数组的值都是字符串名,表示父组件传递过来的数据;
  3. props 的数据,不要直接拿来修改,如果想要修改,必须在 data 上重新定义一个 属性,然后把属性的值 从 this.props 拿过来;

data 上的数据,都是组件自己私有的, data 上的数据,都是可读可写的 props 数据,都是外界传递过来的数据, props 中的数据只能读取,不能重新写入

补充(localStorage 本地存储)

localstorage 存储对象分为两种:
① sessionStrage: session 即会话的意思,在这里的 session 是指用户浏览某个网站时,从进入网站到关闭网站这个时间段,session 对象的有效期就只有这么长。
② localStorage: 将数据保存在客户端硬件设备上,不管它是什么,意思就是下次打开计算机时候数据还在。
两者区别就是一个作为临时保存,一个长期保存。

localStorage 的存储,读取,删除方法
参考博客:localStorage的存储,读取,删除

你可能感兴趣的