Vue2.x基础

14 篇文章 0 订阅

`

第一遍Vue:

MVVM

Model View ViewModel

  • view(视图层)在我们前端开发中,通常就是DOM层,主要是给用户展示各种信息

  • Model (数据层) 数据可能使我们固定死的数据,更多的是来自我们服务器,从网络上请求下来的数据,在我们计数器案例中,就是后面抽取出来的obj,当然,里面的数据可能没有那么简单、

  • VueModel(视图模型层)视图模型层是View和Model沟通的桥梁,一方面它实现了DataBinding,也就是数据绑定,将Model的改变实时的反应到View中,另一方面它实现了DOM Listener,也就是监听DOM,当DOM发生一些事件(点击,滚动,touch)时,可以监听到,并在需要的情况下改变对应的Data

基本结构

1.导入开发版本的vue.js

2.创建vue实例对象,设置el属性和data属性

3.使用简介的模板语法把数据渲染到页面上

<body>
    <div id="app">
      {{ message }}
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
      var app = new Vue({
        el: "#app",
        data: {
          message:"hello world   你好,小黑!"
        }
      })
    </script>
</body>
el:挂载点

vue实例的作用范围 是什么呢?

是否可以使用其他的选择器?

是否可以设置其他的DOM元素?

0.el是用来设置vue实例挂载(管理)

1.vue会管理el选项命中的元素极其内部的后代元素

2.可以使用其他的选择器,但是建议使用id选择器

3.可以使用其他的双标签,不能使用html ,body

补充 挂载点可以传入字符串或者 DOM对象

data:属性对象

1.vue中用到的数据定义在data中

2.data中可以写复杂类型的数据

3.渲染复杂类型数据时,遵守js的语法即可

补充 data中可以传入object 或者 是一个函数(组件中data必须是一个函数)

本地应用(vue指令)

通过vue使用常见的网页效果

学习vue指令,以案例巩固知识点

vue指令指的是,以v-开头的一组特殊语法

v-once v-pre

v-once:解析一次,当vue实例中的数据发生变化,页面重新渲染时,该元素的内容不再更新,维持第一次解析渲染的结果

v-pre: 当需要吧 {{ message }} 原封不动 的解析渲染到页面时候,加上这个指令,该指令会让Vue不再对 mustache 语法进行解析 让她直接渲染出来

v-cloak:

把 mustache 没有渲染的时候 遮罩起来,避免胡子被用户看到

v-text:

1.v-text指令的作用是:设置标签的内容(textContent)

2.默认写法替换全部内容,使用==插值表达式 {{ }}==可以替换指定内容

3.内部支持写表达式

设置标签的文本值,使用v-text方法设置文本会覆盖标签中原本的元素。不想全部替换的话请使用插值表达式

<body>
  <div id="app">
    <h2 v-text="message + '!'"></h2>
    <h5>{{ message + "!" }} </h5>
  </div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
  // 创建Vue实例,得到ViewModel
   var vm = new Vue({
      el:'#app',
      data:{
        message:"hello world"
      },
      methods:{}
   })
</script>

v-text字符串拼接直接 + ‘字符串’ 即可 ,差值表达式需要在 双括号内 + “字符串”

v-html:

1.v-html指令的作用是:设置元素的innerHTML

2.内容中有html结构会被解析为标签

3.v-text指令无论内容是什么,只会解析为文本

4.解析文本使用v-text,需要解析html结构使用v-html

v-on:

1.v-on指令的作用是:为元素绑定事件

2.事件名不需要写on

3.指令可以简写为@

4.绑定的方法定义在methods属性中

5方法内部通过this关键字可以访问定义在data中数据

补充:

1.事件绑定的方法写成函数调用的形式,可以传入自定义参数

2.定义方法时需要定义形参来接收传入的实参

3.事件的后面跟上 .修饰符可以对事件进行限制

4…enter可以限制触发按键为回车

5.事件修饰符有多种

事件修饰符如:.stop .prevent .capture .self .once

关于事件监听方法传参问题

1.当v-on绑定的方法不传参,或者省略括号,而定义方法中传一个参的话,则该参数默认为 事件对象 event

2.当v-on绑定的方法不传参,而定义方法中传参的话,且超过一个以上参数,则第一个参数默认为 event事件对象,其他参数为undefind

3.如果在事件绑定中,不想省略 event事件对象的参数的话 则 使用 $event 传参。

 <div id="app">
    <h2 v-text="message"></h2>
    <input type="button" value="点我" v-on:mouseleave=fn v-on:mouseenter=fn>
    <input type="button" value="进来" v-on:mouseenter=fn>
    <input type="button" value="加数据" v-on:click=fn2>
  </div>
var vm = new Vue({
      el:'#app',
      data:{
        message:"hello world"
      },
      methods:{
        fn: function(){
          console.log(this.message);
        },
        fn2:function () {  
          this.message += "ok"
        }
      }
   })
计数器:

1.创建vue示例时:el挂载点,data数据,methods方法

2.v-on指令的作用是绑定事件,简写为@

3.方法中通过this,关键字获取data中的数据

4.v-text指令的作用是:设置元素的文本值,简写{{}}

5.v-html指令的作用是:设置元素的innerHTML

v-show:

1.v-show指令的作用是:根据真假切换元素的显示状态

2.原理是修改元素的display,实现隐藏

3.指令后面的内容,最终都会解析为布尔

4.值为true元素显示,值为false元素隐藏

5.数据改变之后,对应元素的显示状态会同步更新

v-if:

1…v-if指令的作用是:根据 表达式的真假切换元素的显示状态

2.本质是通过曹总dom元素来切换显示状态

3.表达式的值为true,元素存在于dom树中,为false,从dom树中移除

4.频繁的切换v-show,反之使用v-if,前者的切换消耗小

v-bind:

1.v-bind指令的作用是:为元素绑定属性

2.完整写法是 v-bind:属性,名

3.简写的话可以直接省略v-bind,只保留:属性名

4.需要动态的增删class建议使用对象的方式,当然三元表达式也可以,注意变量与常量

<div id="app">
    <img v-bind:src="imgSrc" alt="" :title="imgTitle+'!!!!!!'">
    <br>
    <img :src="imgSrc" alt="" :title="imgTitle+'!!!!!!'" :class="{active:imgBorder}" @click="isBorder">
    <br>
    <img :src="imgSrc" alt="" :title="imgTitle+'!!!!!!'" :class="imgBorder?'active':''" @click="isBorder">
  </div>
 var vm = new Vue({
      el:'#app',
      data:{
        imgSrc:"http://www.itheima.com/images/logo.png",
        imgTitle:"黑马程序员",
        imgBorder:false
      },
      methods:{
        isBorder:function(){
          this.imgBorder = !this.imgBorder
        }
      }
     })
图片切换:

1.列表数据使用数组保存

2.v-bind指令可以设置元素属性,比如src

3.v-show和v-if都可以切换元素的显示状态,频繁切换使用v-show

<style> 
    *{margin: 0;padding: 0;}
    .bgc{
      position: relative;
      margin: 100px auto;
      width: 500px;
      background-color: #ccc;
    }
    .bgc img{
      width: 100%;
    }
    a{
      position: absolute;
      width: 40px;
      height: 80px;
      line-height: 80px;
      color: rgba(0, 0, 0, 0.452);
      background-color: rgb(255, 0, 0,.4);
      text-decoration: none;
      font-size: 50px;
    }
    a:first-child{
      top: 50%;
      transform: translateY(-50%);
    }
    a:last-child{
      right: 0;
      top: 50%;
      transform: translateY(-50%);
    }
  </style>
</head>
<body>
  <div id="mask">
    <div class="bgc">
        <a href="javascript:;" @click="prev" v-show="index>0" >&lt;</a>
        <img :src="imgArr[index]" alt="">
        <a href="javascript:;" @click="next" v-show="index < imgArr.length-1" >&gt;</a>
    </div>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script>
    var app = new Vue({
      el:"#mask",
      data:{
        imgArr:["img/1.jpg","img/2.jpg","img/3.jpg","img/4.jpg","img/5.jpg"],
        index : 1
      },
      methods:{
        // 改变index  使得图片改变
        prev:function(){
          this.index--
        },
        next:function(){
          this.index++
        }
      }
    })
v-for:

1.v-for指令的作用是:根据数据生成列表结构

2.数组经常和 v-for 一起使用

3.语法 : (item,index)in 数据

4.item 和 index 可以结合其他指令一起使用

5.数组长度的更新会同步到页面上,是响应式的

 <div id="app">
    <input type="button" value="添加" @click="addPeople">
    <input type="button" value="删除" @click="removePeople">
    <ul>
      <li v-for="item in vegetables">
        {{ item }}
      </li>
    </ul>
    <h2 v-for="(item,index) in peoples">
      {{ index+1 }} --- {{ item.name }}=>年龄:{{ item.age }} 性别:{{ item.gender }}
    </h2>
  </div>
  var vm = new Vue({
      el:'#app',
      data:{
        vegetables: ["西红柿","丝瓜","番茄","猪肉","黄瓜"],
        peoples:[{name:"孙悟空",age:18,gender:"男"},{name:"猪八戒",age:22,gender:"男"},{name:"白骨精",age:16,gender:"女"}]
      },
      methods:{
        addPeople:function(){
          this.peoples.push({name:"二郎神",age:26,gender:"不明"})
        },
        removePeople:function(){
          this.peoples.shift()
        }
      }
     })
v-model:

1.v-model指令的作用是便捷的设置和获取表单元素的值

2.绑定数据会和表单元素的值相关联

3.绑定的数据 <---- ----->表单元素的值

记事本:
<!DOCTYPE html>
<html lang="cn">
<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>Document</title>
   <style>
     *{margin: 0; padding: 0;}
     body{background-color: rgb(240, 236, 236);}
     ul{list-style: none;}
     a{text-decoration: none;}
     #wrap{
      position: relative;
      margin: 50px auto;
      width: 800px;
      background-color:  rgb(240, 236, 236);
     }
     #wrap .header{
       width: 100%;
       text-align: center;
       margin-bottom: 20px;
     }
     h2{
       font-family: "微软雅黑";
       font-size:50px;
       font-weight: lighter;
       color: #8C3F37;
     }
     #wrap .content{
      position: relative;
      z-index: 99;
      margin: 0 auto;
      width: 500px;
      background-color: #eee;
      box-shadow: 3px 3px 30px 1px rgba(0, 0, 0, 0.6);
     }
     #wrap .content input{
       box-sizing: border-box;
       padding-left: 8px;
       width: 100%;
       height: 60px;
       background-color: rgba(233, 232, 232, 0.6);
       border: none;
       border-bottom: 1px solid #ccc;
       font-size: 23px;
       color: rgb(126, 126, 126);
       outline: none;
       outline-color: rgba(255, 255, 255, 0);
     }
     #wrap .content ul li{
       box-sizing: border-box;
       padding-left: 8px;
       width: 100%;
       height: 60px;
       line-height: 60px;
       background-color: rgba(233, 232, 232, 0.6);
       border: none;
       border-bottom: 1px solid #ccc;
       font-size: 23px;
       color: rgb(126, 126, 126);
       outline: none;
       outline-color: rgba(255, 255, 255, 0);
     }
     #wrap .content ul li span,#wrap .content ul li h4{
       float: left;
       margin-right: 20px;
       font-weight: 100;
     }
     #wrap .content ul li a{
       float: right;
       padding-right: 10px;
       font-size: 30px;
       color: rgb(126, 126, 126);
     }
     #wrap .bottom{
       display: flex;
       justify-content:space-between;
       width: 100%;
       height: 30px;
       background-color: rgba(233, 232, 232, 0.6);
       border: none;
       border-bottom: 1px solid #ccc;
     }
     #wrap .bottom span{
       padding: 0 15px;
       font-size: 15px;
       color: rgb(78, 77, 77);
       line-height: 30px;
       background-color: rgba(233, 232, 232, 0.6);
       cursor:pointer 
     }
   </style>
</head>
<body>
   <div id="app">
      <section id="wrap">
          <div class="header">
            <h2>小王记事本</h2>
          </div>
          <div class="content">
            <input type="text" autofocus="true" required="required" placeholder="输入事件"  autocomplete="off" v-model="message" @keydown.enter="addNote" >
            <ul>
              <li v-for="(item,index) in notepad" @mouseenter="show(index)" @mouseleave="hide(index)">
                <span>{{ index+1 }}.</span>
                <h4>{{ item.message }}</h4>
                <a href="javascript:;" @click="removeNote(index)" v-show="item.flag">×</a>
              </li>
            </ul>
            <div class="bottom">
             <span v-show="notepad != ''">{{ notepad.length }} items left</span>
             <span v-show="notepad != ''" @click="empty">Clear</span>
            </div>
          </div>
        </section>
   </div>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script>
  // 创建Vue实例,得到ViewModel
   var vm = new Vue({
      el:'#app',
      data:{
        message:"",
        notepad:[],
        val:"",
        
      },
      methods:{
        addNote:function(){
          if(!this.message){
            return
          }
          var obj = {message:this.message,flag:false}
          this.notepad.push(obj)
          this.message = ""
        },
        removeNote:function (index) {  
          this.notepad.splice(index,1)
        },
        empty: function () {  
          this.notepad.splice(0,this.notepad.length)
        },
        show:function(index){
          this.notepad[index].flag = true
        },
        hide:function(index){
          this.notepad[index].flag = false
        }
      }
     })
  </script>
</body>
</html>

网络应用

axios:

官网地址 : https://github.com/axios/axios

1.axios必须先导包,才可以使用

2.使用get或post即可发送相应的请求

3.then方法中的回调函数会在请求成功或者失败时触发

4.通过回调函数的形参可以获取响应内容或者错误信息

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

简单用法:

axios.get(地址?key=value&key2=values).then(function(response){},function(err){})					     //get请求
axios.post(地址,{key:value&key2:values}).then(function(response){},function(err){})      //post请求 

两个测试接口:

1.笑话接口(get): https://autumnfish.cn/api/joke/list 参数名num 参数说明:笑话条数,类型Number

2.用户注册接口(post):https://autumnfish.cn/api/user/reg 参数名: username 参数说明:用户名 备注:不能为空

axios + Vue:

本身没有依赖关系,导入先后无没有关系。

1.axios回调函数中的this已经改变,无法访问到data中的数据

2.把this保存起来,回调函数中直接使用保存的this即可

3.和本地应用的最大区别就是改变了数据来源

天知道查询天气

接口:http://wthrcdn.etouch.cn/weather_mini GET 请求参数:city

<!DOCTYPE html>
<html lang="cn">
<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>Document</title>
  <link rel="stylesheet" href="./css/mini.css">
</head>
<body>
  <div id="app" class="weather-wrap">
    <div class="header"><img src="./img/weaher-logo.png" alt=""></div>
    <div class="content">
        <input type="text" class="city-input" v-model="city" @keydown.enter="searchWeather">
        <input type="button" value="搜索" class="city-search" @click="searchWeather">
    </div>
    <div class="hot-city">
      <span  @click="hotCity('北京')">北京</span>
      <span  @click="hotCity('上海')">上海</span>
      <span  @click="hotCity('杭州')">杭州</span>
      <span  @click="hotCity('宣城')">宣城</span>
    </div>
    <ul class="weather-list">
      <li v-for="item in weather">
        <p v-text="item.type"></p>
        <div>
          <span v-text="item.low"></span>
          <span v-text="item.high"></span>
          <p v-text="item.date"></p>
        </div>
      </li>
    </ul>
  </div>
  <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script src="./js/min.js"></script>
</body>
</html>
 *{margin: 0;padding: 0;}
body{
 background-color: #000;
}
ul{
  list-style: none;
}
.weather-wrap{
  margin: 150px auto;
  width: 1080px;
  height: 800px;
  text-align: center;
}
.weather-wrap .content{
  margin: 0 auto;
  width: 584px;
  overflow: hidden;;
}
.weather-wrap .city-input{
  float: left;
  width: 500px;
  height: 30px;
  font-size: 18px;
  background-color: #000;
  /* border:none; */
  color: #fff;
}
.weather-wrap .city-search{
 float: left;
  width: 80px;
  height: 34px;
  background-color: #fff;
  border: none;
  font-size: 17px;
}

.weather-wrap .hot-city{
  margin: 0 auto;
  width: 584px;
  text-align: left;
}
.weather-wrap .hot-city span{
  color: ivory;
  font-size: 12px;
  cursor: pointer;
}
.weather-wrap .weather-list {
  display: flex;
  justify-content: space-around;
  margin: 90px auto;
  width: 900px;

}
/* .weather-wrap .weather-list li:nth-child(2n){
   border-left: 1px solid rgba(255, 255, 255, .4);
   border-right: 1px solid rgba(255, 255, 255, .4);
} */
.weather-wrap .weather-list li p:first-child{
  color: orange;
  font-size: 30px;
  font-weight: 500;
}
.weather-wrap .weather-list li span{
 font-size: 12px;
 color: orange;
}
.weather-wrap .weather-list li p:last-child{
 font-size: 12px;
 color: #ccc;
}
window.onload = function () {  
// 创建Vue实例,得到ViewModel
 var vm = new Vue({
  el:'#app',
  data:{
    city:"",
    weather:[]
  },
  methods:{
    searchWeather:function () {  
      // http://wthrcdn.etouch.cn/weather_mini
      axios.get('http://wthrcdn.etouch.cn/weather_mini?city=' +this.city)
        .then((respones)=>{
        this.weather = respones.data.data==undefined?[{date:"",high:"",low:"",type:"没有查询到该城市的天气"}]:respones.data.data.forecast;
      },(err)=>{
        console.log(err);
      })
    },
    hotCity: function (c) {  
      this.city = c
      this.searchWeather()
    }
  }
 })
}

综合应用

功能:

1.歌曲搜索

2.歌曲播放

3.歌曲封面

4.歌曲评论

5.播放动画

6.mv播放

接口:https://autumnfish.cn/search 请求方法 get 请求参数 keywords 响应内容:歌曲搜索结果

歌曲url地址获取接口 : https://autumnfish.cn/song/url 请求方法 get 请求参数 id 响应内容:歌曲url

歌曲url地址获取接口 : https://autumnfish.cn/song/detail 请求方法 get 请求参数 ids 响应内容:歌曲详情

热门评论接口 https://autumnfish.cn/comment/hot?type=0 请求方法 get 请求参数 id (歌曲id,type固定为0) 响应内容:歌曲热门评论

mv接口地址: https://autumnfish.cn/mv/url 请求方法 get 请求参数 id (mvid,为0说明没有mv) 响应内容:mv地址

第二遍Vue

ES6

let:

作用域:

ES5之前因为if和for都没有块级作用域的概念,所以在很多时候,我们都必须借助于function的作用域来解决应用外面变量的问题

ES6中,加入了let ,let 它是有 if 和 for 的块级作用域的

1.变量作用域:变量在什么范围内是可用

{
    var name = 'why';
    console.log(name);
}
    console.log(name);

2.没有块级作用域引起的问题:if 的块级

var func;
if (true) {
    var name = 'why';
    func = function () {
        console.log(name);
    }
    // func()
}
name = 'pike'   
func() // 我们并不希望这里调用的时候,前面if作用域中的name  被修改 

3.没有块级作用域引起的问题:for 的块级;

原来的做法是用函数的闭包,因为函数是一个作用域。ES5中函数也是一个作用域

var btns = document.getElementsByTagName('button');
for (var i=0; i<btn.length; i++){
    btns[i].addEventListener('click',function(){
        console.log('第'+ i + '个按钮被点击')
    })
}
// 由于 var 声明在for中没有块级作用域,因此 此处一旦触发了点击事件,打印的永远是遍历最后一次的 i 的 值
{btns[i].addEventListener('click',function(){console.log('第'+ i + '个按钮被点击')
})    i=0}
{btns[i].addEventListener('click',function(){console.log('第'+ i + '个按钮被点击')
})    i=1}
{btns[i].addEventListener('click',function(){console.log('第'+ i + '个按钮被点击')
})    i=2}
...  //这样的遍历操作   由于 i  是var声明的  因此for中的i 是同一个,循环结束后  i 是最后一次的赋值

//可以用函数闭包的方式解决
for (var i=0; i<btn.length; i++){
    (function(i){
        btns[i].addEventListener('click',function(){
        console.log('第'+ i + '个按钮被点击')
    	})
    })(i)
}
// 这样每次回调拿的  都是 这个函数作用域中的i 值  ,该值不会被其他作用域改变

es6 使用 let 声明,此时 该声明的变量 有 块级作用域

var btns = document.getElementsByTagName('button');
for (let i=0; i<btn.length; i++){
    btns[i].addEventListener('click',function(){
        console.log('第'+ i + '个按钮被点击')
    })
}
const :

1.注意一: 一旦给const修饰的标识符被赋值之后,不能修改

2.注意二: 在使用const 定义的标识符,必须进行赋值

3.注意三:常量的含义是指向的对象不能修改,但是可以改变对象的内部属性

对象自面量的增强写法

const obj = { }

1.属性的增强写法

const name = 'why';
const age = 18;
const height = 1.88;

// ES5的写法
const obj = {
    name: name,
    age: age,
    height: height
};

// ES6 的写法
const obj = {
    name,
    age,
    height
};

2.函数的增强写法

// ES5写法
const obj = {
    run: function () { console.log('跑'); },
    eat: function () { console.log('吃'); }
}

// ES6写法
const obj = {
    run(){ console.log('跑'); },
    eat(){ console.log('吃'); }
}

v-bind绑定style

1.动态绑定style

<h2 :style="{ backgroundColor: 'pink', color: 'yellow'}" > 哈哈哈</h2>
 <h2 v-cloak :style="getStyle()" >{{ message }}</h2>

计算属性 computed

computed:{
      fullname: function(){
          return this.firstName + this.lastName
      }
  },

元素中调用的时候不需要加 () ,虽然定义的是一个方法,但是由于是计算属性, Vue内部了一系列处理,使用的时候直接当属性使用即可

内部原理,有set 和 get两个函数,当对这个属性进行赋值时候就会出发set函数,一般不做赋值处理,因此 就可以使用语法糖 直接简写

computed: {
      fullName:{
        set: function(newValue){
            const names = newValue.split(' ');
            this.firstName = names[0];
            this.lastName = names[1]
            // 当对这个计算属性  fullName  赋值时候就会出发set函数 app.fullName = 'Huang mengxiang'
        },
        get: function(){  
            return this.firstName + ' ' + this.lastName
        }
      }
  },

**注意:!**这类计算属性值的操作尽量使用 computed 而不是使用 methods 定义方法,原因是 计算属性的性能比定义方法更高,Vue 内部会对数据监控,一旦计算属性发生变化才会调用这个计算属性的函数,否则内部会进行缓存,直接使用。

事件监听的常用事件对象

  • .stop 调用event.stoppropagation()事件
  • .prevent 阻止默认事件,调用event.preventdefault();
  • .capture 添加侦听事件的时候使用capture模式
  • .self     只当事件是从侦听器绑定的元素本身触发时才回调
  • .{keyCode |keyalias}  只当事件是从侦听器绑定的元素本身触发时才回调
  • .native     监听组件根元素的原生事件
    • 注意组件上监听事件@事件操作符 是无效的,只能通过 修饰符. native后才能监听

v-if,v-else,v-else-if

<div id="app">
    <h2 v-if="score>90">优秀</h2>
    <h2 v-else-if="score>80">良好</h2>
    <h2 v-else-if="score>60">及格</h2>
    <h2 v-else="score<60">不及格</h2>
    <!-- 建议复杂的情况使用计算属性 -->
    <h1>{{ result }}</h1>
  </div>
const app = new Vue({
    el: "#app",
    data: {
        score: 92
    },
    computed: {
        result() {
            let grade = '';
            if (this.score > 90) { grade = '优秀'} else if (this.score > 80) {grade = '良好'} else if (this.score > 60{
            grade = '及格'} else {grade = '不及格'}
            return grade;
        }
    },
    methods: {}
})

vue 数组修改数据响应式

  • push 在数组的最后面添加元素(可传多个)
  • pop 删除数组中的最后一个元素
  • shift 删除数组中的第一个元素
  • unshift 在数组的最前面添加元素(可传多个)
  • splice 删除元素/插入元素/替换元素
  • sort 元素排序
  • reverse 数组中数据顺序反转

以上是响应式的数组函数,在函数调用更改数据后,页面也会得到响应式的 渲染

注意 通过索引值 修改数组中的元素不是响应式的

如 this.letters[0] = ‘bbbb’ 此时数据 letters中的第0个数据被改为’bbbb’ 但是页面并没有响应式渲染。 这种方式 Vue中没有进行监听,因此不是响应式的

  • 也可以使用Vue的内部函数 set 做到响应式修改
  • Vue.set( 要修改的对象 , 索引值 , 修改后的值)
    • Vue.set( 0 ,1 ,‘bbbb’)

过滤器

filters: {
        showPrice(price) {
          return '¥' + parseFloat(price).toFixed(2)
        }
      }
 <td>{{ item.price |  showPrice}}</td>

默认过滤器中的方法会将 | 前面的参数传入,最终return 回一个处理好的数据 ,此时 元素上也会显示处理好的数据

关于for循环的3种方式

for(let i=0; i<arr.length; i++){
    
}
for(let i in arr){
    // i 为 arr中每一项索引
}
for(let item of arr){
     // item 为 arr中每一项
}

1.编程范式:

  • 命令式编程
  • 声明式编程(Vue react)

2.编程范式:

区分方式看第一公民

  • 面向对象编程 (第一公民:对象)
  • 函数式编程 (第一公民:函数)
    • 可进行很多链式编程

三个高阶数组函数

filter / map / reduce

1.filter中的回调函数有一个要求:必须返回一个boolean值,true:当返回true时,函数内部会自动将这次回调的n加入到新的数组中,false:当返回false时,则会过滤到这次的n

2.map 中的回调函数 对原数组进行一个映射,可以将每个 n 进行一系列操作,然后 return 返回,此时新数组就会将这个return 值 加入

3.reduce 传递两个参数,第一个参数为回调函数,第二个参数为初始值。 回调函数中传递两个参数,一个是上次的计算值,第一次的时候直接等于初始值,第二个参数是回调每次拿到的数组中的遍历对象。 在回调中返回 第一个参数跟 拿到的遍历对象之间的操作。 该函数会直接返回最终 计算的值

 const nums = [123, 222, 1, 6, 66, 88, 145, 69, 77, 61]
 
 let result = nums.filter(n => n < 90).map(n => n + 33).reduce((pre, n) => pre + n, 0)
 console.log(result);

v-model 补充

​ 原理:其实就是一个语法糖,他的背后本质上是包含两个操作:

  • v-bind 绑定一个value属性
  • v-on 指令给当前元素绑定input事件

也就是说下面的代码: 等同于下面的代码

<input type="text" v-model="message">
//  等同于
<input type="text" :value="message" @input="message=$event.target.value">
v-model : select

和 checkbox 一样,select也分单选和多选

单选:只能选中一个值

  • v-model绑定一个值
  • 当我们选中option中的一个时,会将它对应的value赋值到mySelect中

多选:可以选中多个值

  • v-model绑定的是一个数组
  • 当选中多个值时,就会将选中的option对应的value添加到数组mySelects中

单选

<div id="app">
    <select v-model="fruits" >
      <option value="苹果">苹果</option>
      <option value="橘子">橘子</option>
      <option value="香蕉">香蕉</option>
      <option value="梨子">梨子</option>
      <option value="榴莲">榴莲</option>
    </select>
    <h2>水果是:{{ fruits }}</h2>
  </div>

  <script src="./lib/vue-2.4.0.js"></script>
  <script>
    const app = new Vue({
      el: "#app",
      data: {
        fruits: ''
      },
      methods: {}
    })
  </script>

多选

  <div id="app">
    <select v-model="fruits" multiple>
      <option value="苹果">苹果</option>
      <option value="橘子">橘子</option>
      <option value="香蕉">香蕉</option>
      <option value="梨子">梨子</option>
      <option value="榴莲">榴莲</option>
    </select>
    <h2>水果是:{{ fruits }}</h2>
  </div>

  <script src="./lib/vue-2.4.0.js"></script>
  <script>
    const app = new Vue({
      el: "#app",
      data: {
        fruits: []
      },
      methods: {}
    })
  </script>
v-model : radio
  <div id="app">
    <label for="man">
      <input type="radio" name="sex" id="man" v-model="sex" value=""></label>
    <label for="woman">
      <input type="radio" name="sex" id="woman" v-model="sex" value=""></label>
    <h2>性别是: {{ sex }} </h2>
  </div>

  <script src="./lib/vue-2.4.0.js"></script>
  <script>
    const app = new Vue({
      el: "#app",
      data: {
        sex: ''
      },
      methods: {}
    })
  </script>
v-model :checkbox
   <div id="app">
    <h2>你喜欢的运动</h2>
    <input type="checkbox" name="" id="" v-model="spots" value="篮球">篮球
    <input type="checkbox" name="" id="" v-model="spots" value="羽毛球">羽毛球
    <input type="checkbox" name="" id="" v-model="spots" value="电竞">电竞
    <input type="checkbox" name="" id="" v-model="spots" value="睡觉">睡觉
    <input type="checkbox" name="" id="" v-model="spots" value="乒乓球">乒乓球
    <input type="checkbox" name="" id="" v-model="spots" value="足球">足球
    <h2>你喜欢的运动有:{{ spots }} </h2>
  </div>

  <script src="./lib/vue-2.4.0.js"></script>
  <script>
    const app = new Vue({
      el: "#app",
      data: {
        spots: []
      },
      methods: {}
    })
  </script>
简单理解

v-model 是多项选择的话 绑定数据请使用数组, 单项选择使用字符串

v-model 修饰符
  • lazy 修饰符 input失去焦点 和 回车的时候进行数据更新
  • number (默认情况下,v-model 默认绑定为字符串类型)
    • 此时使用number 修饰符可以将输入的数据 转为number 类型存储
  • trim 修饰符 ,可以将绑定的数据前后空格去除

组件化(以上为基础)

基本

分三步:

  1. Vue.extend({})
  2. Vue.component(‘使用时候的标签名’,创建的组件名)
  3. html中使用
  • 创建组建
	// 1. 创建组建
    const cpnConstructor = Vue.extend({
      template: `
      <ul>
        <li>你愁啥</li>
        <li>瞅你咋地</li>
        <li>不咋地</li>
        <li>在瞅个试试</li>
      </ul>
      `
    })
  • 注册组件
	// 2.注册组件
    Vue.component('my-cpn', cpnConstructor)
  • 使用组件
 	<!-- 3.使用组建 -->
    <my-cpn></my-cpn>
全局组件,局部组件

1.全局组件注册是在全局作用域中

2.局部组件注册是在局部作用域中(Vue实例中)

<script>
    const cpnConstructor = Vue.extend({
        template:` <ul>
                    <li>你愁啥</li>
                    <li>瞅你咋地</li>
                    <li>不咋地</li>
                    <li>在瞅个试试</li>
                  </ul>`
    })
    const app = new Vue({
        el: "#app",
        data: {
            sex: ''
        },
        methods: {},
        components:{
            myCpn: cpnConstructor
        }
    })
</script>

此处注意,js中使用的 驼峰命名的 标签 myCpn 当在html中当标签使用的时候,标签名 应将大写字母改为小写,且 在该字母前面加上 <my-cpn> </my-cpn>

父子组件

1.创建好组件构造器

2.当在全局中注册则为全局组件,在局部注册则为局部组件,局部组件只能在局部使用,当在其他地方使用的时候,会报错,显示找不到该组件

3.父子组件是相对的,组件在另一个组件中注册的时候,该组件则为另一个组件的子组件。

4.通过 Vue.extend() 传递一个对象可以实例化一个 组件构造器,对象中的参数 template 属性定义组件模板,后面还有一个 components属性 ,该属性跟Vue实例中的components属性用法一致,当使用该属性为一个组件注册后,则称为被注册组件的父组件

5.子组件只能在父组件中使用,而且是在 父组件的 模板 tempalte中使用

 <div id="app">
    <cpn2></cpn2>
  </div>
 <script>
    const cpnC1 = Vue.extend({
      template: `<ul><li>你愁啥111</li><li>瞅你咋地11</li><li>不咋地11</li><li>在瞅个试试11</li></ul>`
    })
    const cpnC2 = Vue.extend({
      template: `
      <ul>
        <cpn1></cpn1>
        <li>你愁啥222</li>
        <li>瞅你咋地222</li>
        <li>不咋地22</li>
        <li>在瞅个试试22</li>
      </ul>
      `,
      components: {
        cpn1: cpnC1
      }
    })


    const app = new Vue({
      el: "#app",
      data: {},
      methods: {},
      components: {
        cpn2: cpnC2
      }
    })
语法糖注册组件方式(推荐)
// 1.全局注册组件语法糖方式
Vue.component('my-cpn', {
    template: '<div><h2>你好啊</h2><p>世界</p></div>'
})
// 2.局部注册组件的语法糖方式
const app = new Vue({
    el: "#app",
    data: {},
    methods: {},
    components: {
        myCpn2: {
            template: `<div><h2>Hello</h2><p>World</p></div>`
        }
    }
})

关键点: 原本的 组件构造器 Vue.extend( template: 模板) 直接改为了{template:模板}

原本传 组件构造器的 地方直接改为 {template:模板},将注册跟创建构造器合在了一起,由Vue内部自行处理, 其实Vue内部也是调用了 Vue.extend( template: 模板) 构造器,然后再将构造器传到注册中

组件模板的分离写法
  1. script 标签写法
  2. 使用template标签
<!-- 1.script 标签写法 -->
  <script type="text/x-template" id="cpn">
    <div>
        <h2>hello world</h2>
        <ul>
          <li>你说啥</li>
          <li>什么</li>
          <li>啊啊</li>
        </ul>
    </div>
  </script>
<!-- 2.使用template标签 -->
  <template id="cpn2">
    <div>
      <h2>hello world</h2>
      <ul>
        <li>????</li>
        <li>!!!</li>
        <li>ee</li>
      </ul>
    </div>
  </template>

注意!!!!组件不能访问Vue实例数据

组件是一个单独功能模块的封装

组件中 的数据是保存在哪里?

Vue 组件应该有自己保存数据的地方,那个地方就是注册组件的位置,除l template属性 components 属性 还有 data属性,该属性用于保存组件的数据

该属性 data 的值是一个函数,必须有返回值, return 一个对象

components: {
    cpn: {
        template: '#cpn2',
            data(){
            return {
                title:'abc'
            }
        }
    }
}
为什么组件的data必须是一个函数

1.组件本身是会被多次使用的,如果data不是一个函数, 而是一个对象,则每次给组件的data数据都是同一个内存地址上的数据,也就是说所有该组件使用的是同一个data数据,这就会导致当一个组件的data数据更改后,其他组件都会因为这个改变而产生连锁的改变。这样会导致很多问题

如下:直观感受为什么Vue设计的时候 组件data是一个函数

function func(){
    return {name:'jack',age:18}
}
let obj1 =  func()
let obj2 =  func()
let obj3 =  func()
// 此时改变其中一个对象的属性
obj1.name = 'mike'
// obj2   obj3  并不会受到影响
// 因为每次调用func()的时候  ,函数会开辟一块内存,存储创建的对象,因此三次函数调用返回的对象,其实是不同的内存地址


//反观 如下  则会影响
let obj = {name:'aaa',age:11}
function func2(){
    return obj
}
let obj11 =  func2()
let obj22 =  func2()
let obj33 =  func2()
obj11.name = 'bbb'
// 影响的原因是  obj指向了一块存有  {name:'aaa',age:11} 的内存地址, 函数func2 返回值 就是这个地址,每次都一样
// 所以 这三个对象指向的内存地址都一样,因此一个改变,则所有指向该地址的对象都会被改变
父子组件的通信

子组件是不能引用父组件或者Vue实例的数据

但是在开发中,往往一些数据确实需要从上层传递到下层

  • 比如在一个页面中,我们从服务器请求到了很多的数据
  • 其中一部分的数据,并非是我们整个页面的大组件来展示的,而是需要下面的子组件来展示
  • 这个时候,并不会让自组建再次发送一个网络请求,而是直接让大组件(父组件)将数据传递给小组件(子组件)

如何进行父子组件之间的通信呢

  • 通过 props 向子组件传递数据
  • 通过事件 向父组件发送消息
props 基本用法

注意!!! js代码给props 名称命名为 驼峰的话,则 v-bind绑定的时候 需要将大写改为小写,并在前面加 杠 -

在组件中,使用选项props来声明需要从父级接收到的数据

props的值有两种方式:

  • 方式一:字符串数组,数组中的字符串就是传递时的名称
  • 方式二:对象,对象可以设置传递时 的类型,也可以设置默认值 (推荐,用的较多
<div id="app">
    <cpn :cmovies="movies" :cmessage="message"></cpn>
  </div>

  <template id="cpn">
    <div>
      <ul>
        <li v-for="item in cmovies">{{ item }}</li>
      </ul>
      <h2>{{ cmessage }}</h2>
    </div>
  </template>
  <script src="./lib/vue-2.4.0.js"></script>
  <script>
    const cpn = {
      template: '#cpn',
      props: ['cmovies', 'cmessage']
    }

    const app = new Vue({
      el: "#app",
      data: {
        message: "helloWorld",
        movies: ['西游记', '三国演义', '水浒传', '红楼梦']
      },
      methods: {},
      components: {
        cpn
      }
    })
  </script>

注意 props传递的名称用 v-bind 绑定在组件的标签上 不是绑定在模板上!!!!!!!!!!!

props数据验证
Vue.components('my-cpn',{
    props:{
        // 基础的类型检查  `null`匹配任何类型
        propsA: Number,
        propB: [String,Number],
        propC:{
            String,
            required:true
        },
        // 带有默认值的数字
        propD: {
           type: Number,
           default:100
        },
        propE: {
            type: Object,
            default:function(){
                return {message:'hello'}
            }
        },
        //自定义验证函数
        propF: {
            validator: function(value){
                // 这个值必须匹配下列字符串中的一个
                return ['string','success','warning','danger'].indexOf(value) !== -1
            }
        }
    }
})
//  自定义类型
function Person(firstName, lastName) {
    this.firstName = firstName
    this.lastName = lastName
}

Vue.component('blog-post',{
    props: {
        author: Person
    }
})
子传父

props 用于父组件向子组件传递数据,还有一种比较常见的是子组件传递数据或事件到父组件中

此时我们就需要借助自定义事件来完成传递了

自定义事件的流程:

  • 在子组件中,通过$emit()来出发事件
  • 在父组件中,通过v-on来监听子组件事件

1.创建子组件 , 父组件

2.子组件注册在父组件内部

3.子组件定义一个方法,将要传递的数据作为参数放入这个方法,然后通过 this.$emit('自定义的事件名',传递的参数) 这个方法将 传递的参数发射出去。 然后父组件通过 事件绑定的方式 v-on 绑定这个发射的事件,事件触发的函数定义时候接收一个参数 , 此时传递的参数就是 $event ,父组件不传递参数的话,默认会将 这个参数传递过去, 从而完成了 父组件访问 子组件内部的数据

<body>
  <div id="app">
    <cpn1></cpn1>
  </div>

  <!-- 父组件 -->
  <template id="cpn1">
    <div>
      <div>
        <h2>hello world</h2>
        <cpn2 @itemclick="show($event)"></cpn2>
        <h2>{{ message }}</h2>
      </div>
    </div>
  </template>

  <!-- 子组件 -->
  <template id="cpn2">
    <div>
      <button v-for="item in categories" @click="btnClick(item)">{{ item.name }}</button>
    </div>
  </template>

  <script src="./lib/vue-2.4.0.js"></script>
  <script>
      
    // 定义子组件构造器(虽然是一个对象,但是注册时候,vue内部会调用Vue.extend())
    const cpn2 = {
      template: '#cpn2',
      data() {
        return {
          categories: [
            {id: 'aaa',name: '可乐'},
            {id: 'bbb',name: 'pingguo'}, 
            {id: 'ccc',   name: '向iao' }, 
            {id: 'ddd',   name: 'iaohuas' }, 
            {id: 'eee',   name: '苹果' }]
        }
      },
      methods: {
        btnClick(item) {
          this.$emit('itemclick', item)
        }
      }
    }
    // 注册父组件
    Vue.component('cpn1', {
      template: '#cpn1',
      data() {
        return {
          message: []
        }
      },
      components: {
        cpn2
      },
      methods: {
        show(item) {
          this.message.push(item.name)
        }
      }
    })

    const app = new Vue({
      el: "#app",
      data: {},
      methods: {}
    })
  </script>
</body>
重点:

不论是子传父 ,还是父传子,都是在子组件构造器中定义,父传子,子组件中定义props , 子传父 ,在子组件中调用 this.$emit()方法,然后在 父组件区域内的子组件上进行配置

  • 父传子,子组件定义props,然后在父组件区域的子组件标签上绑定属性,拿到属性值(父组件的数据),然后子组件直接将绑定的属性作为数据使用,如果想要更改绑定的属性值,不能直接更改,只能通过子组件的data属性将props中的属性赋值给data中,然后通过子传父更改父组件中的data数据,从而改掉props中的值
  • 子传父,子组件通过方法调用,将数据作为参数传递给这个方法。 然后同过 this. e m i t ( ) 发 射 一 个 事 件 , t h i s . emit() 发射一个事件,this. emit()this.emit() 有两个参数,第一个是事件的名称,第二个是接收的数据。然后 在父组件区域的子组件标签上进行该事件监听,调用父组件的一个方法,该方法的 $event 就是我们传递的数据

父子组件的访问方式
父访问子

$children $refs

有时候我们 需要父组件直接访问子组件,子组件直接访问父组件,或者是子组件访问根组件

  • 父组件访问子组件:使用 $children $refs
  • 子组件访问父组件:使用$parent

先来看下$children的访问

  • this.$children 是一个数组类型,它包括所有子组件对象
  • 我们这里通过一个遍历,取出所有子组件的message
   const app = new Vue({
      el: "#app",
      data: {},
      methods: {
        callOn() {
          // console.log(this.$children);
          // this.$children[0].showDate()
          console.log(this.$refs);
          this.$refs.ccc.showDate()
        }
      },
      components: {
        cpn: {
          template: '#cpn',
          data() {
            return {
              message: ['海王', '海泽日晚', '海贼王', '海尔兄弟']
            }
          },
          methods: {
            showDate() {
              console.log(this.message);
            }
          }
        }
      }
    })

$refs 使用

1.直接在父组件的 方法中调用 this.$refs 得到的是一个空数组,要想获取子组件信息, 需要在 父组件区域的子组件标签上 加上属性 ref

2**.ref这个属性的属性值就是得到这个子组件的 属性名**。 到时候直接调用 this.$refs.属性名 即可访问子组件

子访问父

$parent

在子组件定义方法,通过 this.$parent 拿到父组件,该组件在哪个父组件中注册,并使用了注册时候的方法,则获取的就是对应的父组件,只有一个父组件

访问根组件

$root

ref的使用
  • ref如果是绑定在组件中,那么通过this.$refs.refname获取到的是一个组件对象
  • ref如果是绑定在普通的元素中,那么通过this.$refs.refname获取到的就是一个元素对象

——————————————————————————————————————————

组件化高级

插槽

1.slot

  • 组件模板定义的时候需要插槽的话 给一对 <slot> </slot> 标签即可, 在使用子组件的时候,组件内部填充的所有内容,元素就会被匹配到这个插槽上
  • 本身 <slot> </slot> 可以给一个默认值,该默认值 在使用这个组件 没有给插槽内容的时候会自动使用

2.具名插槽 slot

  • 组件模板定义的时候插入 <slot> </slot> 插槽,此时子组件被使用时候,内部插入内容就会匹配到这个插槽,因为二者都没有名字,因此能够匹配 ,当 <slot name='center'> </slot> 当定义模板使用插槽 给插槽一个名字的时候,那么 直接内部使用标签填充则不会匹配到这个插槽, 只有当 使用 slot=“center” 才能匹配到这个插槽 如 <span slot='center'>我匹配到了</span>

注意 : 2.6版本起 该具名插槽方式已被废弃

新的具名插槽方式(**重点!!!!!!!!**2.6版本更新后用法)

  • 组件模板定义的时候插入 <slot> </slot> 插槽,此时子组件被使用时候,内部插入内容就会匹配到这个插槽,因为二者都没有名字,因此能够匹配 ,当 <slot name='center'> </slot> 当定义模板使用插槽 给插槽一个名字的时候,那么 直接内部使用标签填充则不会匹配到这个插槽。此时在父页面使用 <template v-slot:center> </template> 来锁定这个name 为 center 的这个插槽。如果<slot> </slot> 没有name属性的话 ,其实Vue会给它一个 默认的 name 为 default , 因此匿名插槽也可以通过 <template v-slot:default> </template> 来获取这个插槽
编译作用域

Vue 的编译作用域:首先看模板是谁的,那么这个范围内的变量就从谁那里找, 因此子组件模板的作用域就是这个子组件父组件的模板作用域就是这个父组件Vue实例的作用域就是这个实例

作用域插槽( 2.6版本更新后用法 )

作用域插槽是slot 一个比较难理解的点

  • 父组件替换插槽的标签,但是内容由子组件来提供的

1.和具名插槽一样,绑定了插槽之后,由于要获取子组件的数据,或者方法,因此 v-slot:子组件的name值=‘自定义一个名字(该名字用来接收子组件传递的数据)’

2.那么子组件如何将数据传递出去呢?? 直接 :data = “传递的数据” 此时Vue内部会将 父页面自定义的名字与这个 :data 数据绑定起来,此时父页面的 自定义名字 . data 就是 这个 :data 我们就可以通过这个方式 将数据传到父 页面 ,供父页面使用

<body>
  <div id="app">
    <cpn></cpn>
    <cpn>
      <template v-slot:data="slotProps">
        <h2>{{slotProps.user}}</h2>
      </template>
    </cpn>
  </div>

  <template id="cpn">
    <div>
      <slot name="data" :user="pLanguages">
        <ul>
          <li v-for="item in pLanguages">{{ item }}</li>
        </ul>
      </slot>
    </div>
  </template>

  <script src="./lib/vue.js"></script>
  <script>
    const app = new Vue({
      el: "#app",
      data: {},
      methods: {},
      components: {
        'cpn': {
          template: '#cpn',
          methods: {
            show() {
              return console.log(123);
            }
          },
          data() {
            return {
              pLanguages: ['JavaScript', 'C', 'C++', 'Java', 'C#', 'Pathon'],
              user: {
                lastName: '123',
                firstName: 'wyj'
              }
            }
          }
        }
      }
    })
  </script>
</body>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值