vue系列【一】

131 阅读9分钟

1、下载并安装webstorm

image.png

2、创建项目

2.1 new project

image.png

2.2 安装配合和依赖

2.2.1 安装router及vuex

vue add router
vue add vuex

2.2.1.1 报错及处理

vue : 无法加载文件 C:\Users\Administrator\AppData\Roaming\npm\vue.ps1,因为在此系统上禁止运行脚本。有关详细信息,请参阅 https:/go.microsoft.com/fwlink/?LinkID=135170 中的 about_Execution_Policies。

2.2.1.2 原因

windows上设置了策略是禁止未受信任的脚本运行,所以修改策略。

2.2.1.3 解决

  • 管理员身份运行终端了powershell

  • 执行命令:set-ExecutionPolicy RemoteSigned

  • 选择Y

image.png

2.2.2 安装element-plus:element-plus.org/zh-CN/guide…

npm install element-plus --save

2.3 配置main.js

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'

// 如果你对打包后的文件大小不是很在乎,那么使用完整导入会更方便
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'

const app = createApp(App)
app.use(ElementPlus).use(store).use(router).mount('#app')

3、vue指令

vue中有很多指令,放在标签上,以v-开头的,称之为指令,每个指令都能完成相应操作;

<p v-html='js变量,函数,表达式'> </p>

3.1 文本指令(操作文本相关)

# v-html:把变量的内容当html渲染到标签中去(字符串是标签,会完整渲染)

# v-text:把变量内容当字符串写到到标签中(字符串是标签,不会渲染成标签),如果原来标签有内容,会去掉
	-可以完成跟 {{}} 一样的功能,但是还是不一样的

# v-show:只能跟 truefalse  或   表达式运算结果是布尔类型,控制标签的显示与否
		-
# v-if :只能跟 truefalse  或   表达式运算结果是布尔类型,控制标签的显示与否

# vue中面试题:v-if和v-show区别是什么?
    -v-if:如果是false,不显示,标签也不存在(删除和添加标签,效率低)
    -v-show,如果是false,不显示,但是标签存在,只是通过样式 dispaly=none控制是否显示;

3.2 事件指令

# v-xx 放在标签中就是指令,指令就能完成不同的功能
# v-on:事件名='函数'    : 给这个标签绑定一个事件,当触发这个事件,就会执行函数
    -事件:click,blur,dbclick。。。很多
    -函数 必须写在methods 对象内,可以使用es6的对象写法
# 重点:
    v-on:事件名='函数'    可以简写成      @事件名='函数'(以后都用它)

# 补充
    -html:标签
      -css:样式(好看)  bootstrap是css样式,element-ui
      -js:动起来        jquery是js框架,vue是js框架,react

3.3 属性指令

# v-bind:属性名="变量"
    -标签会有很多属性 <a href=""></a>   <img src="" >  <p name="xxx"></p> <button class="btn">点我</button>
    -可以绑定标签的任意属性
    -v-bind可以简写成 : -----> :属性='变量'

4、style和class

# 属性指令:style和class属性特殊一点


#  // class属性可以绑定:字符串,数组(常用,class由多个类组成,数组跟它最搭),对象
#  // style 属性可以绑定: 字符串,数组,对象(常用)
  • 示例代码:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="./js/vue.js"></script>
    <title>标题</title>
    <style>
        .red {
            color: crimson;
        }

        .back {
            background: greenyellow;
        }

        .size {
            font-size: 50px;
        }

    </style>
</head>
<body>


<div id="app">
    <h1>class的三种绑定方式</h1>
    <!--    <div :class="class_str">-->
    <!--    <div :class="class_list">-->
    <div :class="class_obj">
        我是一个div
    </div>

    <hr>
    <h1>style的三种绑定方式</h1>
    <!--    <div style="font-size: 50px;background: pink;color: green">-->
    <!--    <div :style="style_str">-->
    <!--    <div :style="style_list">-->
    <div :style="style_obj">
        我是第二个div
    </div>

</div>
</body>

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            // class:字符串,数组(常用,class由多个类组成,数组跟它最搭),对象
            class_str: 'red size',
            class_list: ['red', 'size'], // 如果咱么向数组末尾最近一个类名,div样式就变了,最常用形式
            class_obj: {red: true, size: false, back: false},
            // style :字符串,数组,对象
            style_str: 'font-size: 50px;background: pink',
            style_list: [{'font-size': '50px'}, {'background': 'pink'}, {'color': 'green'}],
            // style_list: [{fontSize: '50px'}, {background: 'pink'}, {color: 'green'}], // 跟上面一样,如果是 - 相连的两个单词可以改成驼峰形式
            style_obj: {fontSize: '50px', background: 'pink', color: 'green'}, // style 来讲,它用的多
        },
        methods: {}
    })

</script>

</html>

5、条件渲染

# 指令:实现符合某个条件,就显示某个标签
v-if  v-else-if   v-else
  • 示例代码:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="./js/vue.js"></script>
    <title>标题</title>
    <style>


    </style>
</head>
<body>


<div id="app">

    <p v-if="score>90">优秀</p>
    <p v-else-if="score>70 && score<=90">良好</p>
    <p v-else-if="score>60 && score<=70">及格</p>
    <p v-else>不及格</p>

</div>
</body>

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

</script>

</html>

6、列表渲染

# v-for 指令
    -可以循环:数组   v-for="(url,index) in urls"      位置不能换
    -可以循环:对象   v-for="(value,key) in obj"       如果只接收一个值,这个值就是value
    -可以循环:数字   v-for="i in num"1开始,循环到数字的个数
  • 示例代码:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="./js/vue.js"></script>
    <title>标题</title>
    <style>


    </style>
</head>
<body>


<div id="app">
    <h1>把所有美女,一行行显示在页面中</h1>

    <ul>
        <!--        <li v-for="url in urls">-->
        <li v-for="(url,index) in urls">
            <h3>第{{index + 1}}张美女</h3>
            <img :src="url" alt="" height="100px" width="100px">
        </li>
    </ul>

    <h1>循环对象</h1>
<!--    <p v-for="(value,key) in obj">key值为:{{key}},value值为:{{value}}</p>-->
    <p v-for="value in obj">value值为:{{value}}</p>


    <h1>循环数字</h1>
    <p v-for="i in num">循环到了第:{{i}}</p>

</div>
</body>

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            urls: ['https://img2.woyaogexing.com/2022/10/13/05e406595e217e0c!400x400.jpg',
                'https://img2.woyaogexing.com/2022/10/13/c03408591b068c18!400x400.jpg',
                'https://img2.woyaogexing.com/2022/10/13/f810d999375f7f1c!400x400.jpg'],
            obj: {name: 'lqz', age: 19, bobby: '篮球'} ,  // hash类型  hashmap  map  字典  对象 都是没有顺序
            num:4

        },
    })

</script>

</html>

7、数据双向绑定

# input :text,password,select...
# text文本类型的双向数据绑定 
    -使用 :value='变量'   单向数据绑定,页面变化,变量不会跟着变---》一般不用
    -使用 v-model='变量'  双向数据绑定,页面变化,变量变化都会相互影响
# 使用
    <input type="text" v-model="v">
  • 示例代码:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="./js/vue.js"></script>
    <link href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">

    <title>标题</title>

</head>
<body>


<div id="app">

    <h1>v-model 只针对于input</h1>
    请输入内容:<input type="text" v-model="v"> ---->{{v}}


</div>
</body>

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

</script>

</html>

8、事件处理

# 事件:click,dbclick   blur,     input,      change。。。
        单击    双击     失去焦点   输入内容      发生变化  
  
# input框会有blur, input, change 事件
  • 示例代码:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="./js/vue.js"></script>

    <title>标题</title>

</head>
<body>


<div id="app">

    <h1>失去焦点事件blur</h1>
    请输入名字:<input type="text" v-model="name" @blur="handleBlur">
    <h1>change事件:数据发生变化才会触发</h1>
    请输入名字:<input type="text" v-model="name" @change="handleChange">
    <h1>input事件:只要输入内容会触发</h1>
    请输入名字:<input type="text" v-model="name" @input="handleInput">


</div>
</body>

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            name: '彭于晏'
        },
        methods: {
            handleBlur() {
                alert(this.name)
            },
            handleChange() {
                console.log(this.name)  // 跟python中print一样
            },
            handleInput(){
                console.log(this.name)
            }
        }
    })

</script>

</html>

8.1 过滤案例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="./js/vue.js"></script>

    <title>标题</title>

</head>
<body>


<div id="app">

    <h1>过滤案例</h1>
    <input type="text" v-model="search" @input="handleInput">
    <ul>
        <li v-for="item in newdataList">{{item}}</li>
    </ul>


</div>
</body>

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            search: '',
            dataList: ['a', 'at', 'atom', 'atommon', 'be', 'beyond', 'cs', 'csrf', 'csrffe'],
            newdataList: ['a', 'at', 'atom', 'atommon', 'be', 'beyond', 'cs', 'csrf', 'csrffe']
        },
        methods: {
            handleInput() {
                // this 指向问题
                // 这个位置this是vue对象
                // var _this = this
                // this.dataList = this.dataList.filter(function (item) {
                //     console.log('----', _this) // this 还是vue对象吗?是浏览器对象
                //     return item.indexOf(_this.search) > -1
                // })

                // 使用es6的语法解决
                this.newdataList = this.dataList.filter(item => {
                    // console.log('----', this) // 如果使用剪头函数,this还是vue(剪头函数没有自己的this)
                    return item.indexOf(this.search) > -1
                })
            }
        }
    })

</script>

</html>
  • 字符串indexOf方法:
// 补充:字符串有个indexOf,返回索引,如果大于-1,表示字字符串在当前字符串中
var s='lqz is handsome'
var res=s.indexOf('zoo') // 如果me在字符串中,就返回me在字符串的索引位置,否则返回-1
console.log(res)
  • 数组filter方法:
// 补充:数组的内置方法,filter,传匿名函数进去,匿名函数如果返回true这个就保留,如果返回false,就不保留

var search = 'a'
var l = ['a', 'at', 'atom', 'atommon', 'be', 'beyond', 'cs', 'csrf', 'csrffe']
var ll = l.filter(function (item) {
return item.indexOf(search) > -1
})
console.log(ll)
  • es6 的箭头函数:
// 传统写法
var a=function (name,age){
    console.log(name)
}

//es6 箭头函数  匿名函数的另一种写法
    var a=  (name,age) =>{
    console.log(name)
}

8.2 时间修饰符

# 放在事件后的
@click.once='函数'

.stop	只处理自己的事件,不再冒泡给父标签(阻止事件冒泡)
.self	只处理自己的事件,子控件冒泡的事件不处理
.prevent	阻止a链接的跳转
.once	事件只会触发一次(适用于抽奖页面)
  • 示例代码:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="./js/vue.js"></script>

    <title>标题</title>

</head>
<body>


<div id="app">

    <h1>点击子标签,父标签的事件也触发:事件冒泡</h1>
    <h2>阻止事件冒泡:点子标签,父标签不触发 stop</h2>
    <ul @click="handleUl">
        <li @click.stop="handleLi">点我看美女</li>
        <li>点我看帅哥</li>
    </ul>

    <h1>点击子标签,父标签的事件也触发:事件冒泡</h1>
    <h2>子标签的冒泡不处理:父标签写self,父标签只处理自己的事件,冒泡的事件不管</h2>
    <ul @click.self="handleUl">
        <li @click="handleLi">点我看美女</li>
        <li>点我看帅哥</li>
    </ul>

    <h1>prevent 阻止a链接的跳转</h1>
    <a href="http://www.liuqingzheng.top" @click.prevent="handleA">点我看美女</a>

    <h1>once 只执行一次</h1>
    <button @click.once="handleButton">点我秒杀</button>


</div>
</body>

<script>
    var vm = new Vue({
        el: '#app',
        data: {},
        methods: {
            handleLi() {
                console.log("li被点击了")
            },
            handleUl() {
                console.log("ul被点击了")
            },
            handleA() {
                console.log('a被点击了,不会再跳转了')
            },
            handleButton() {
                alert('秒杀成功')
            }
        }
    })

</script>

</html>

8.3 按键修饰符

# 事件:input,change   除此之外还有 【按键】被按下和被抬起的事件
  • 示例代码:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="./js/vue.js"></script>

    <title>标题</title>

</head>
<body>


<div id="app">

    <h1>按键修饰符</h1>
<!--    <input type="text" @keyup="handleKeyUp($event)">-->
    <input type="text" @keyup.enter="handleKeyUp($event)">
    <input type="text" @keyup.esc="handleKeyUp($event)">
    <input type="text" @keyup.="handleKeyUp($event)">


</div>
</body>

<script>
    var vm = new Vue({
        el: '#app',
        data: {},
        methods:{
            handleKeyUp(event){
                console.log('sdasfd')
               if(event.code=='Enter') {
                   console.log('enter键被抬起了,开始搜索')
               }
            }
        }

    })

</script>

</html>

9、表单控制

# form表单---》input标签,单选,多选按钮
# 单选,多选的  v-model的绑定

# 1 checkbox的单选---》v-model绑定一个布尔值---》只要选中布尔就为true,反之亦然
# 2 radio的单选----》v-model绑定字符串----》选中字符串就是value对应的值
# 3 checkbox的多选---》v-model绑定一个数组---》多个选中,数组就有多个值
  • 示例代码:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./js/vue.js"></script>
</head>
<body>
<div class="app">
    <h1>表单控制之checkbox单选</h1>

        <p>用户名:<input type="text" v-model="username"></p>
        <p>密码:<input type="password" v-model="password"></p>
        <p><input type="checkbox" v-model="isCheck">记住密码</p>
        <p>
            <input type="radio" v-model="gender" value="1"><input type="radio" v-model="gender" value="2"><input type="radio" v-model="gender" value="0">未知
        </p>
        <p>爱好(多选):</p>
        <p>
            <input type="checkbox" v-model="hobby" value="篮球"> 篮球
            <input type="checkbox" v-model="hobby" value="足球"> 足球
            <input type="checkbox" v-model="hobby" value="橄榄球"> 橄榄球
            <input type="checkbox" v-model="hobby" value="乒乓球"> 乒乓球
        </p>
<!--        <hr>-->
<!--        密码是否选中:{{isCheck}}-->
<!--        <hr>-->
<!--        性别是:{{gender}}-->
<!--        <hr>-->
<!--        爱好是:{{hobby}}-->

        <hr>
        <input type="submit" value="提交" @click="handleSubmit">



</div>

</body>
<script>
    var vm = new Vue({
        el: '.app',
        data: {
            username: '',
            password: '',
            isCheck: false,
            gender: '',
            hobby:[],
        },
        methods: {
            handleSubmit(){
                //假设发送ajax到后端了
                console.log(this.username)
                console.log(this.password)
                console.log(this.isCheck)
                console.log(this.gender)
                console.log(this.hobby)
            }
        },


    })
</script>
</html>

10、js的循环方式

# 1 方式一:最基本的
for (let i=0; i<3; i++) {
  console.log(i)
}

# 2 in 循环  es5的语法
for(let 成员 in 对象){
    循环的代码块
  
  
# 3 for of   es6的循环
  for(item of arr){
    console.log('item =>', item)
  }
  
 
# 4 数组foreach循环 (数组)
   var a=[33,22,888]
   a.forEach(function (value,index){
        console.log(value)
        console.log(index)
    })

# 5 jq  $each 循环
$.each(可迭代对象,function (key,value) {
  });
 
var a=[33,22,888]
 // var obj={name:'lqz',age:19}
 $.each(a,function (key,value){
       console.log(key)
       console.log(value)
   })

11、v-model进阶

# v-model 进阶之 
lazy:双向数据绑定,只要修改输入框的值,就再更新数据,耗费资源,加了lazy后,等不输入了,变量再变化
number:输入框,只接收数字部分,如果输入了  123asdfasd,只保留123 数字部分
trim:  去掉输入内容前后的空白
  • 示例代码:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./js/vue.js"></script>
</head>
<body>
<div class="app">
    <h1>v-model进阶</h1>
    <p><input type="text" v-model.lazy="a">{{a}}</p>
    <p><input type="text" v-model.number="b">{{b}}</p>
    <p><input type="text" v-model.trim="c">{{c}}</p>


</div>

</body>
<script>
    var vm = new Vue({
        el: '.app',
        data: {
          a:'',
          b:'',
          c:'',

        },



    })
</script>
</html>

12、vue生命周期

# 组件化开发
    vue的实例:vm
    以及后面学的组件:vc
    它们有生命周期:从创建开始,到销毁
    vue中总共生命周期有8个钩子函数(4对),依次调用
  
  
# 钩子的意思:aop的体现
    beforeCreate	创建Vue实例,组件实例对象创建 之前调用
    created	创建Vue实例成功后调用(咱们用的对,可以在此处发送ajax请求后端数据)

    beforeMount	渲染DOM之前调用
    mounted	渲染DOM之后调用
    ---初始化完成了----

    beforeUpdate	重新渲染之前调用(数据更新等操作时,控制DOM重新渲染)
    updated	重新渲染完成之后调用
    ---一直在转圈----

    ----销毁组件---
    beforeDestroy	销毁之前调用
    destroyed	销毁之后调用   
  
  
##### 提前讲个组件的概念### 自己写的有html,有样式,有js的好看的可以复用的东西
    -完整看到组件的生命周期
    -vm实例的生命周期看不完整
  
  
###### 重点:
    -created多一些:在这里面发送ajax请求,data的数据好了后,再发请求,去后端拿数据
    -updated:数据变化,页面更新完后,执行它
    -destroyed:组件销毁,会触发它,也会用
    -组件创建了,起了个定时器,不停地打印hello world(每隔一段时间执行一个函数,延迟调用)
    -如果组件销毁了,定时器没有被销毁,会出现定时器还在执行的情况,
    -所以要在destroyed中把定时器取消掉,资源清理工作
    -vm实例和组件实例都有8个生命周期钩子函数
    -只要写了钩子函数,就会执行,不写就不会执行 
  
  
# 面向过程编程
# OOP编程:面向对象编程
# AOP编程:面向切面编程(对面向对象编程的补充),java的spring框架大量的使用
    -python中装饰器  AOP编程的体现
    -drf源码,反序列化的源码,钩子函数,aop体现

13、与后端交互(ajax,fetch和axios)

# 跨域问题: 前后端分离的项目会出现
    -浏览器有个安全策略:不允许向不同域(地址+端口号)发送请求获取数据,浏览器的 同源策略
    -解决跨域:
        -后端的cors(跨域资源共享)技术:就是在响应头中加入允许即可
        -nginx做代理。。。
    
    
# 原生js发送ajax请求,jq发送ajax请求,fetch发送ajax请求,axios发送ajax请求
    -原生:new XMLHttpRequest()   老api,坑很多
    -jq基于它封装,封装出了$.ajax ,屏蔽了很多问题
    -官方觉得XMLHttpRequest坑很多,搞了个fetch,跟XMLHttpRequest是平级的,比它好用,但是不支持ie
    -axios继续基于XMLHttpRequest封装了,一个发送ajax请求的模块

13.1 使用jq的ajax方法

# 原生js写ajax,jq帮咱们写好了,处理好了浏览器版本间的不兼容,可以直接用

$.ajax({
    url: 'http://127.0.0.1:8000/test/',
    type: 'get',
    success: data => {
        // 后端返回json格式字符串,$.ajax拿到字符串,转成了js的对象,给了data
        this.name = data.name
        this.age = data.age
    }
})

13.2 使用fetch方法

fetch('http://127.0.0.1:8000/test/').then(res => res.json()).then(res => {
    console.log(res)
    this.name = res.name
    this.age = res.age
})

13.3 使用第三方,axios(js模块)

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


axios.get('http://127.0.0.1:8000/test/').then(res=>{
    console.log(res.data) // 真正后端给的数据(res.data 才是真正的数据)
    this.name=res.data.name
    this.age=res.data.age
  })

14、计算属性

# 计算属性:
1、以后当属性用  
2、只有关联的数据变化,才重新运算 
3、有缓存,数据没有变化,页面再更新,它也不变化

# 案例:有个input,输入英文后,把首字母变成大写
# 完整写法
computed: {
   // "计算属性名" (){},
    "计算属性名": {
        set(值){

        },
        get(){
            return 值
        }
    }
}
  • 示例代码:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./js/vue.js"></script>
</head>
<body>
<div class="app">
    <h1>计算属性</h1>
    <!--    最简单方式-->
    <h2>最简单方法首字母变大写</h2>
    <!--    <input type="text" v-model="name">-&ndash;&gt;{{name.slice(0, 1).toUpperCase() + name.slice(1)}}-->
    <h2>使用函数实现,页面只要更新,这个函数就会重新执行,比较耗费资源</h2>
    <!--    <input type="text" v-model="name">-&ndash;&gt;{{getUpper()}}-->

    <input type="text" v-model="age">--->{{age}}

    <h3>通过计算属性实现:计算属性只有在它的相关依赖发生改变时才会重新求值</h3>
    <input type="text" v-model="name">--->{{upperName}}

</div>

</body>
<script>
    var vm = new Vue({
        el: '.app',
        data: {
            name: '',
            age: 0
        },
        methods: {
            getUpper() {
                console.log('我执行了')
                return this.name.slice(0, 1).toUpperCase() + this.name.slice(1)
            }
        },
        computed: {
            upperName() {
                console.log('我是计算属性,我执行了')
                return this.name.slice(0, 1).toUpperCase() + this.name.slice(1)
            }
        }


    })
</script>
</html>

15、监听属性

监听属性是Vue.js提供的一种用来监听和响应Vue实例中的数据变化的方式。在监听数据对象中的属性时,每当监听的属性发生变化,都会执行特定的操作。

15.1 watch选项中定义监听属性的示例代码

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            fullname: '韦小宝'
        },
        watch: {
            fullname: function (newValue, oldValue) {
                alert('原值:' + oldValue + '新值:' + newValue)
            }
        },


    })
    vm.fullname = '宋小宝'

</script>
  • 运行结果:

image.png 上述代码中,在watch选项中对fullname属性进行了监听。当改变该属性值的时候,会执行对应的回调函数,函数中的两个参数newValue和oldValue分别表示监听属性的新值和旧值。其中,第二个参数可以省略

15.2 deep选项

如果要监听的属性值是一个对象,为了监听对象内部值的变化,可以在选项参数中设置deep选项的值为true。示例代码如下:

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            shop: {
                name: 'iphone 14',
                price: 5699
            }
        },

        watch: {
            shop: {
                handler: function (val) {
                    alert(val.name + '新价格为' + val.price + '元');
                },
                deep: true
            }
        }
    })
    vm.shop.price = 6599
</script>
  • 运行结果

image.png

16、组件化开发

16.1 全局组件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./js/vue.js"></script>
</head>
<body>
<div class="app">
    <h1>全局组件</h1>
    <navbar></navbar>




</div>

</body>
<script>
    // 定义一个全局组件,在任意组件中都可以使用
    var obj = {
        template: `
          <div>
          <button @click="handleBack">后退</button>
          我是一个组件-->{{name}}
          <button>前进</button>
          </div>
        `,
        data() {
            return {
                name:'lqz'
            }
        }, // 重点,data必须是个函数,返回一个对象,组件可以在多个地方重复使用,如果就是对象,导致多个组件共用同一个对象的数据,出现错乱
        methods: {
            handleBack(){
                alert('后退了')
            }
        },
        // 学的所有放在vm对象中的,都可以用
    }
    Vue.component('navbar', obj)


    var vm = new Vue({
        el: '.app',
        data: {},


    })
</script>
</html>

16.2 局部组件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./js/vue.js"></script>
</head>
<body>
<div class="app">
    <h1>全局组件</h1>
    <navbar></navbar>
    <hr>
    <lqz></lqz>


</div>

</body>
<script>
    // 定义一个全局组件,在任意组件中都可以使用
    var obj = {
        template: `
          <div>

          <button @click="handleBack">后退</button>
          我是一个组件-->{{ name }}
          <button>前进</button>
          </div>
        `,
        data() {
            return {
                name: 'lqz'
            }
        }, // 重点,data必须是个函数,返回一个对象,组件可以在多个地方重复使用,如果就是对象,导致多个组件共用同一个对象的数据,出现错乱
        methods: {
            handleBack() {
                alert('后退了')
            }
        },
        // 学的所有放在vm对象中的,都可以用
        components: {} // 知道就可以了
    }
    Vue.component('navbar', obj)


    var vm = new Vue({
        el: '.app',
        data: {},
        components: {
            lqz: {
                template: `
                  <div>
                  <h3>我是局部组件</h3>
                  <button>点我看美女</button>
                  </div>`,
                data() {
                    return {}
                },
                methods: {}
            }
        }


    })
</script>
</html>

17 组件通信

各个组件间,数据,方法,都是隔离的

17.1 父子通信之父传子(自定义属性)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./js/vue.js"></script>
</head>
<body>
<div class="app">
<h1>通过自定义属性,实现父传子</h1>
    <h3>父组件中name:{{name}}</h3>
    <hr>
    <navbar :myname="name" :age="age"></navbar>    // 对应props中的属性名称
    <hr>

</div>

</body>
<script>
    // 定义一个全局组件,在任意组件中都可以使用

    Vue.component('navbar', {
        template: `
        <div>
        <button>前进</button>
        名字是:{{myname}}--->年龄是:{{age}}    // 调用变量
        <button>后退</button>
        </div>`,
        props:['myname','age']    //定义属性名称
    })


    var vm = new Vue({
        el: '.app',
        data: {
            name:'彭于晏',
            age:99
        },


    })
</script>
</html>

17.2 父子通信之子传父(自定义事件)

子组件点击按钮=>子组件执行函数this.$emit('自定义事件名字') =》注册在组件上的【自定义事件】对应的函数执行

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./js/vue.js"></script>
</head>
<body>
<div class="app">
    <h1>通过自定义事件,实现子传父</h1>
    <h3>父组件中收到子组件传递对值为:{{name}}</h3>
    <hr>
    <navbar @myevent="handleReceive"></navbar>
    <hr>

</div>

</body>
<script>
    Vue.component('navbar', {
        template: `
          <div>

          <input type="text" v-model="iname">---》{{ iname }}
          <br>
          <button @click="handleClick">点我吧iname传递到父组件中</button>

          </div>`,
        data() {
            return {
                iname: ''
            }
        },
        methods: {
            handleClick() {
                // 触发自定义事件的执行,并且传入当前组件中的iname
                this.$emit('myevent', this.iname)    // 固定写法,第一个是触发的事件名称,后面为需传入的参数
                // alert(this.iname)
            }
        }
    })

    var vm = new Vue({
        el: '.app',
        data: {
            name: '',
        },
        methods: {
            handleReceive(iname) {
                this.name = iname
            }
        }

    })

  //子组件点击按钮=>子组件执行函数this.$emit('自定义事件名字') =》注册在组件上的【自定义事件】对应的函数执行
</script>
</html>

17.3 ref属性

# 组件间通信---》通过ref属性,vue提供了一个ref属性,可以放在任意标签
	-放在普通标签,通过  this.$refs.ref对应的名字    就能拿到原生dom对象,使用原生操作该dom
  -放在自定义组件上,通过 this.$refs.ref对应的名字 就能拿到 组件对象,就可以调用对象的函数,使用对象的变量
    -父组件中,拿到了子组件对象,对象中的属性,方法可以直接用,直接改  
 	
  
# 通过ref,子传父
    -因为在父中,可以拿到子的对象,子对象中的所有变量,方法,都可以直接用
# 通过ref,实现父传子
    -因为在父中,可以拿到子的对象, 子对象.变量=父的变量
  

# vuex---》实现跨组件间通信
  • 示例代码:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./js/vue.js"></script>
</head>
<body>
<div class="app">
    <h1>ref实现组件间通信</h1>
    {{name}}<br>
    <input type="text" v-model="name" ref="myinput">
    <button @click="handleClick">点我打印</button>
    <hr>
    <navbar ref="mynavbar"></navbar>
    <hr>
    <button @click="handleClick1">点我</button>


</div>

</body>
<script>
    Vue.component('navbar', {
        template: `
          <div>
          <input type="text" v-model="iname">---》{{ iname }}
          <br>
          </div>`,
        data() {
            return {
                iname: ''
            }
        },
        methods: {
            handleClick() {
                console.log('执行了')
                return 'xxx'
            }
        }
    })
    var vm = new Vue({
        el: '.app',
        data: {
            name: '',
        },
        methods: {
            handleClick() {
                console.log(this.$refs.myinput)
                console.log(this.$refs.myinput.value)
                this.$refs.myinput.value = 'lqz is big'
                alert(this.name)
            },
            handleClick1(){
                console.log(this.$refs.mynavbar) // 相当于拿到了再组件中的this(组件对象)
                console.log(this.$refs.mynavbar.iname)
                // this.name=this.$refs.mynavbar.iname
                // 父组件中直接执行子组件的方法
                // this.$refs.mynavbar.handleClick() // 调用子组件的方法
                this.$refs.mynavbar.iname='sssss'


            }
        }


    })

</script>
</html>

18、动态组件

<component> 元素,动态地绑定多个组件到它的 is 属性
<keep-alive> 保留状态,避免重新渲染

# 场景: 组件是谁不确定,通过 is 确定显示那个组件
  • 示例代码:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./js/vue.js"></script>
</head>
<body>
<div class="app">
    <h1>动态组件</h1>
    <ul>
        <li @click="myType='home'">首页</li>
        <li @click="myType='goods'">商品</li>
        <li @click="myType='shopping'">购物</li>
    </ul>
    <!--    动态组件,is是哪个组件名字,这里就会显示那个组件-->
    
    <keep-alive>     // 保留状态,避免重新渲染
        <component :is="myType"></component>
    </keep-alive>
</div>

</body>
<script>

    Vue.component('home', {
        template: `
            <div>
                <h2>首页</h2>
            </div>`
    })

    Vue.component('goods', {
        template: `
            <div>
                <h2>商品</h2>
                要搜索的商品:<input type="text">    // 通过keep-alive保留上次搜索内容
            </div>`
    })

    Vue.component('shopping', {
        template: `
            <div>
                <h2>购物</h2>
            </div>`
    })


    var vm = new Vue({
        el: '.app',
        data: {
            myType: 'home',
        },


    })

    //子组件点击按钮=>子组件执行函数this.$emit('自定义事件名字') =》注册在组件上的【自定义事件】对应的函数执行
</script>
</html>

19、插槽

19.1 不具名插槽

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./js/vue.js"></script>
</head>
<body>
<div class="app">
    <h1>插槽</h1>
    <hr>
    <home>
        <div>
            <img src="https://pic.maizuo.com/usr/movie/0c5874a81c7969c8eb7ddee7b6ff46b3.jpg" alt="" width="200px"
                 height="300px">
        </div>
    </home>
    <hr>

    <home>
        <div>
            我是div
        </div>
    </home>

</div>

</body>
<script>

    Vue.component('home', {
        template: `
            <div>
                <h2>首页</h2>
                
               <!-- 核心部分 -->
                <slot></slot>
            </div>`
    })

    var vm = new Vue({
        el: '.app',
        data: {
            myType: 'home',
        },
    })

</script>
</html>

19.2 具名插槽

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./js/vue.js"></script>
</head>
<body>
<div class="app">
    <h1>插槽</h1>
    <hr>
    <home>
        <img src="https://pic.maizuo.com/usr/movie/0c5874a81c7969c8eb7ddee7b6ff46b3.jpg" alt="" width="200px"
             height="300px" slot="bottom">
        <div slot="top">
            我是div
        </div>
    </home>
    <hr>


</div>

</body>
<script>

    Vue.component('home', {
        template: `
            <div>
                <slot name="top"></slot>
                <p>我是子组件</p>
                <slot name="bottom"></slot>

            </div>`
    })

    var vm = new Vue({
        el: '.app',
        data: {
            myType: 'home',
        },


    })


</script>
</html>