黑马高大神 vue框架 第五天

day5
1.组件的生命周期 创建到销毁的整个过程
        v-if创建并且删除元素
一个组件 标签就是一个组件的实例
        v-if会造成组件的创建和销毁


2.钩子函数 
初始 beforeCreate 创建实例过程 created
挂载 beforeMount 挂载过程 mounted 挂载完成 已经有dom了
更新节点 beforeUpdate 更新过程 updated 数据驱动视图
销毁阶段 beforeDestory 销毁过程 destoryed 一般在beforeDestroy中销毁 因为beforeDestory方法中是已经确定了要销毁的数据了

3.初始化阶段
created才可以用data和methods方法
beforeCreated是鸡肋
CRUD 查询 created-data和methods已经使用了
查询网络请求在created中

4.挂载阶段  模板编译  虚拟dom到真实dom  挂载到页面
挂载 beforeMount 挂载过程 mounted 挂载完成 已经有dom了
beforeMount 是鸡肋  几乎不用
mounted 获取真实dom --echarts
echarts.init(dom)//一般在mouted中进行 获取真实dom

5.更新阶段  数据变化 触发钩子函数
export default(){
    data(){
    return{
            a:1,
            b:2
},
beforeUpdate(){

    
},
update(){

}
}}
watch侦听单个的变量,二update是所有变量的触发  都会执行
还是watch更精细  
created 和mounted 虚拟dom到真实dom的和销毁之前的阶段是常用的

6.销毁阶段
beforeDestory 销毁所有的监视器  和事件 destroyed
销毁被全局引用的变量  --定时器

created获取数据  mounted获取dom beforeDestroy--销毁定时器相关的引用

7.axios的介绍
请求的库 --客户端使用  nodejs也可以使用
支持promise
主流的请求工具库  

npm i axios

用法:
axios({
    method:"get/post/put/delete/patch",
    url:"",//请求的接口地址
    data:{}, //请求体参数  body参数  post/put/delete/patch
    parms:{}//地址参数 url参数  拼接到url地址上

//箭头函数 一个参数不用写括号
}).then(result=>{
    //result是返回结果
}).catch(error=>{
    //error 报错结果
})
get获取数据  没有请求体参数
post提交数据
put 更新数据 完整更新{id:1,name:"aijing"} 数据完全覆盖
patch 增量更新 部分更新 只更新name属性
delete 删除

axios.get('地址').then({retsult获取结果})


解析:axios.then().catch()
axios返回一个Promise对象
三种状态: pending(等待) 成功 失败
new Promist(function(resolve,reject){
    resolve()//成功
    reject()//失败
}).then(result=>{}).catch(error=>{

})

axios的实现机制 源代码
function axios(){

其结果返回一个  Promise       成功和失败
    return new Promise (function (resolve,reject){
    //resolve()
    XMLHttpRequest  xml=new XMLHttpRequest()
    xml.open('get'," ")
    xml.send()
    xml.οnlοad=function(){
        resolve(JSON.parse(xml.response))
    }
    xml.οnerrοr=function(){
        reject()
    }
    })
}
axios().then(result=>{

})

npm i axios
import axios from 'axios'

channels:[],//频道列表
created(){
创建的时候调用方法
    this.getChannleds()
},
methods:{
    getChannleds(){
    axios({
            url:"http://toutiao.itheima.net/v1_0/channels"  
    }).then(({data})=>{   //解构赋值   解构数据   
         log(data.data.channels)
this.channels=data.data.channels
    }
}
}
<li v-for="(item,index) in channels" :key="index">
          {{ item }}
</li>

2.axios 发起post请求
绘制页面结构
login.vue

在login里面
<template>
  <div>
    <!-- 登录页面结构 -->
    <h1>短信登录</h1>
    <div class="form_item">
      <input
        class="input_item"
        type="text"
        v-model.trim="mobile"  //双向绑定输入的手机号
        placeholder="请输入手机号"
      />
    </div>
    <div class="form_item">
      <input
        class="input_item code"
        type="text"
        placeholder="请输入短信验证码"
        v-model.trim="code"   //双向绑定  输入的验证码    输入了就保存到data的code数据中
      />

      <span class="send_code">发送验证码</span>
    </div>
    <div class="form_item">
      <button class="btn_login" @click="login">登录</button>    //点击登录按钮  触发事件
    </div>
  </div>
</template>

<script>
import axios from 'axios' //导入axios
export default {
  name: "LoginCom",
  data() {
    return {
      mobile: "19906398784",
      code: "246810",
    };
  },
  methods: {
    // 校验手机号的格式和验证码的格式
    // 手机号
    login() {
      // 手机号和验证码  校验输入的手机号和验证码是符合规则的
      const mobileReg=/^1[3-9]\d{9}$/
      const codeReg=/^\d{6}$/
      if(mobileReg.test(this.mobile)&&codeReg.test(this.code)){
        // 此时两个都通过了验证
        // 调用接口登录
        // http://toutiao.itheima.net/app/v1_0/authorizetions
        axios.post('http://toutiao.itheima.net/v1_0/authorizations',{
          mobile:this.mobile,
          code:this.code,
        }).then(()=>{
          alert('登录成功')
        }).catch(()=>{
          alert('用户的手机号或密码错误')
        });
        // axios({
        //   url:"",
        //   data:{},
        //   method:{}
        // })
        //默认的验证码 246810 
      }else{
        alert("用户的手机号或密码错 ")
      }
    },
  },
};
</script>

发送验证码倒计时功能
默认 没有发送验证码状态  初始为0
timerCount:0//默认为0
在发送验证码  大于0就是显示倒计时  =0和<0就是重置 可以再次请求验证码
 {{timerCount >0 ? `${timerCount}秒` : '发送验证码'}}


给发送验证码的按钮添加点击事件
@click='sendCode'
sendCode(){
const mobileReg=/^1[3-9]\d{9}$/
const codeReg=/^\d{6}$/
    //判断当前的时间>0 不能发送  请求地址
// https://toutiao.itheima.net/v1_0/sms/codes/19906398784
    if(this.timerCount ===0 &&mobileReg.test(this.mobile){
        只有在=0和 输入的手机号 符合手机号的规则 的情况下 才能发送验证码 
      axios.get(`https://toutiao.itheima.net/v1_0/sms/code/${this.mobile}`)//发起请求校验输入的手机号  发送验证码
this.timerCount=10//开启倒计时
this.timer=setInterval(()=>{
    if(this.timerCount===0){
            clearInterval(this.timer)
    }else{
        this.timer--    
    }
},1000)
    }
}

11.配置axios的基地址
axios的路径要完整  不易维护 只需要配置一个地方  所有的请求都会生效
axios.defaults.baseURL='https://toutiao.itheima.net'

axios可以创建实例  //相当于new创建实例
const instance=axios.create({
    baseURL='https://toutiao.itheima.net'
})  

instance.get()
instance.post()
这样的好处  不会影响原始数据

在导入的地方配置基地址
axios.defaults.baseURL='https://toutiao.itheima.net'

12.ref获取dom元素  
因为双向绑定 数据绑定视图 数据驱动视图
 给想要获取dom 的标签上一个ref属性
div ref='abc'
<login-com ref='efg'//组件的标签  获取组件的实例对象
必须在mounted和以后的生命周期函数
this.$refs.abc  这个就是真实的dom对象

this.$refs.属性  父组件拿到子组件的this
this.$parent      子组件拿到父组件 的this

13 ref实现父传子
确定父子关系
给子组件的标签添加一个ref属性
this.$refs.属性获取子组件的实例this
通过实例就可以调用方法 来传值

14.$nextTick方法
等到数据渲染完成 dom更新之后执行
this.$nextTick(函数体)
Vue.nextTIck(函数体)  两个一样

export default{
    methods:{
            update(){
                    this.count++//更新数据
                    this.$nextTick(()=>{
                    渲染更新完成之后   此时获取最新的数据
                                  }
                        }
            }
}
nextTick应用场景: 在需要获取更新的dom时候,或者props传值
因为props更新要重新渲染   也是一个异步过程 
父组件调用子组件的方法
ref-获取子组件的实例   this  通过this就可以获取子组件的方法 和属性
子组件的属性有Props属性  不能保证已经更新完成
nextTick执行的时候  说明渲染完成  数据也更新完成了

当你遇到获取的数据是上一次的时候  说明你遇到了异步  可以使用 nextTick

15.json-server的使用
json 开启服务器
是一个npm包  快速生成8个接口  包括增删改查
npm i -g json-server

新建json文件
{
    这里的数据写在这里

}
启动服务
json-server ./da.json --watch
相当于有了后台服务  有接口了


17.获取数据显示到购物车上面
json-server
axios
安装axios
npm i axios
在main.js入口文件 引入
imoort axios from 'axios'

配置基地址   我这里是json-server启动的服务端口  里面是接口数据
axios.deafults.baseURL='http://localhost:3000'

在app.vue
导入axios
list:[]
created(){
    this.getGoodsList()
}
getGoodsList(){
    axios.get('/goodsList').then(({data}){
        this.list=data
    })
}
得到数据 在goods-item组件中渲染数据   父传子
<goods-item v-for='item in list' :key='item.id' :item='item'>

在goods-item组件 接受数据
 props:['item']
得到数据  渲染数据
{{item.goods_name}}
{{item.goods_price}}
{{item.goods_count}}
img :src='goods.img'

1.购物车选中问题
1.checkbox想要点击图片也选中  通过label的属性for='id' id不能写死  因为商品列表是循环出来的  应该生成动态的id和动态的for
只有label标签的for绑定多选框   二者要一致
input type='checkbox' :id=`input_${item.id}`>
label :for='`input_${item.id}`'

2.绑定单选框影响的购物车数据
Props数据单向数据流   修改的数据  回到父组件  改变父组件的属性
这个id是为了绑定label  checked=接收其状态 因为是单向 不能监听其值 只是负责展示  绑定改变事件
input type='checkbox' :id=`input_${item.id}` :checked='item.goods_state'
@change='changeChecked'>

changeChecked(event){
    event.target.checked//得到当前的状态
这里是我是子组件 通过props获取到item项 通过this指向获取props的id  传递当前的这个input
this.$emit('updateChecked',this.item.id,event.target.checked) //id是当前任务项    第二个参数是当前任务项的状态  是true还是false
}

在父组件
goods-item v-for='item in list' :key='item.id' :item='item' @updateChecked='updateChecked'

updateChecked(id,godds_state){
    //修改数组的状态
push pop shift unshift splice sort reverse
重新赋值一个新数组  新数组和原数组的长度一样
this.list=this.list.map((item)=>{
    数组有几条  遍历多少次
if(item.id===id)//找到了在子组件点击的那个input的id项
将子组件传递的状态给新数组  再渲染到页面上
item.goods_state=goods_state;
    return item;
})
}

在子组件中 v-model绑定props数据不允许  是单向数据流
将数据显示到组件上  绑定了input的checked数据
监听input的change事件
通过子传父 this.$emit(事件名称,参数)将改变的值和id传递给父组件
在父组件中监听这个传递的自定义事件  再改变自己的list数组 
重新生成一个新数组  找到对应的项的id 从而改变其状态

3.全选状态的设定
全选组件在footer组件中  状态的展示依赖list数组中的状态state是否全部都勾选了

通过计算属性来监听其list的state值的状态
computed(){
isAll(){
计算是不是所有的state都勾选了
有这个一个方法every()  判断是不是所有的item项都等于true
[true,true,false].every(item =>item===true) //false

// every方法会返回 true和false   这里的item.goods_state  是item.goods_state===true的简写
return this.list.every(item =>item.goods_state)
}
}
将计算属性得到的值传递给子组件 cart-footer   值会返回ture还是false
cart-footer :isAll='isAll'

在子组件接受props:['isAll']
给input全选多选框动态绑定  :checked='isAll' 这个会返回true和false  true就是勾选  false反之

绑定全选多选框的状态和  传递一个事件   实现反选的功能
input :checked='isAll' @change='updateAll'
updateAll(event){
这里没有id  这是全选按钮只有一个 true就是true   false就是false
this.$emit("updateAll",event.target.checked)

}

在父组件监听
cart-footer :isAll='isAll' @updateAll='updateAll'
要将所有的状态都跟新传过来的状态  实现全选按钮的反选
updateAll(goods_state){

重新赋值一个新数组  新数组和原数组的长度一样
this.list=this.list.map((item)=>{
    数组有几条  遍历多少次
这里是所有的item的state状态 不是true 就是false 绑定的所有的state
item.goods_state=goods_state
return item
})

}
全选状态的设定 小结
全选组件在footer组件中  将状态的展示依赖list中的item项是否全部都勾选了  其子组件的状态是父组件传递过来的  因为是单向数据流 不能在子组件去修改父组件的值
父组件中定义计算属性  判断所有的item项map一下  看有没有全部都选中
将计算属性的结果 传递给footer组件  赋值给checked属性 如果list的state状态都勾选就是true 那么传递过去的就是true 拿全选按钮就是true勾选
监听input的值去改变事件
触发自定义事件  将true/false传递给父组件
父组件监听事件
根据true/false来影响list全部的state状态


5.算出总数量 和总价格  显示在footer组件上
找到所有勾选的item项 && 价格*数量的总和就是=总价格
总数量=选中的商品的数量总和
在父组件的计算属性 计算总价格和总数量
computed(){
//总价格
totalPrice(){
    这里的item是对象  返回reduce方法的结果
    return this.list.reduce((preValue,item)=>{
    这里要是勾选的item.goods_state为true就算到总数量中 
    我这里的return是回调函数的return
    //return preValue+item.goods_count; 
    对返回的结果修改一下 状态为true就计算  false就+0   再去乘以价格
    return preValue +(item.goods_state? item.goods_count:0) *item.goods_price
},0)
    要把三元表达式包裹起来  再跟之前的preValue加
这里的总价格 就是把总数量的复制过来  *总价格
因为 reduce方法是前面两个数加的和再跟后一位值再加   数量再*价格就是总价格的数量

}
},
//总数量
totalCount(){
reduce方法 第一个参数是回调函数(preValue,currentItem){
},0)
[1,2,3].reduce(function(preValue,currentItem){
    return preValue+currentItem //1+2的结果+3 =6
},0)

这里的item是对象  返回reduce方法的结果
return this.list.reduce((preValue,item)=>{
这里要是勾选的item.goods_state为true就算到总数量中 
    我这里的return是回调函数的return
    return preValue+item.goods_count; 
对返回的结果修改一下 状态为true就计算  false就+0
return preValue +(item.goods_state?item.goods_count:0)
},0)
要把三元表达式包裹起来  再跟之前的preValue加

}
}
将总数量的计算属性结果返回给子组件 显示到页面上
cart-footer :totalCount='totalCount' :totalPrice='totalPrice' :isAll='isAll' @updateAll='updateAll'

在footer子组件得到值总数量的结果  totalCount是总数量   totalPrice是总价格
props:['isAll','totalCount','totalPrice']
得到数据  渲染页面
{{totalCount}}
{{totalPrice}}

购物车案例 到此结束  感谢观看


5.动态组件
一个位置可以切换不同类型的组件
用到vue的内置组件 component
<component :is='变量'
变量是组件的名字 --注册组件 的名字

1.如果要展示多少个组件  就要创建多少个vue组件
在views目录下新建组件
在app引入组件 注册组件  写组件标签
在components目录新建8个组件
在views目录下的changeFace组件导入8个组件

changeFace组件写:
动态组件:
data数据 faceName=''
<component :is='faceName'></component>
button @click='changeFace'
方法
changeFace(){
获取随机数 随机8 +1是得到组件8
const value=~~(Math.random()*8)+1

    this.faceName=`CommonFace${value}`
}
<component is='组件名称'></component>是内置组件 需要is绑定组件名称

6.组件缓存:
目的是提示性能  创建一次  就不会销毁了
缓存我们的组件实例  保留虚拟dom  销毁真实dom

vue提供一个内置组件  <keep-alive>包裹组件  就不会销毁
<keep-alive>
    <alive-test></ alive-test>
</keep-alive>
用keep-alive包裹的组件 就会保留虚拟dom  不会销毁 提示性能
想让谁缓存 就用keep-alive包裹

7.组件缓存的钩子函数
用keep-alive包裹的组件不再执行   生命周期的函数
激活事件 -从缓存中再次被引用  activated()
休眠事件-将其放入缓存 deactivated()

export default{
    activated(){
组件被激活
}

deactivated(){
组件被休眠
}
}

8.插槽 
组件展示不同结构的内容  使用插槽
挖坑:代表使用vue内置组件 <slot></slot>
填坑:组件标签内部的内容就是坑的内容

组件标签中的内容就是插槽的内容
<alive-test>
    插槽的内容
    
</alive-test>

插槽这里的课程有噪音  直接跳过

12.自定义指令
自己编写指令
if else show bind on for model text html slot once pre
v-once只渲染一次 响应式的更新
v-pre 跳过当前标签的扫描 写了很多层级的页面结构

可以自定义指令
全局 局部
export default{
    directives:{
    focus:{
        //inserted 作用的标签被插入到dom之后执行这个函数
        inserted(el,options){
    el.focus();
}
}
}
}


day5的小结:
1.生命周期  四个阶段 八个钩子函数
初始化阶段 beforeCreate created  实例化前后触发
created获取数据 因为次时的data和methods已经初始化
挂载阶段:beforeMount mounted dom挂载前后触发
mounted 获取dom对象
数据更新阶段:beforeUpdate updated  数据更新前后触发
很少用  监听所有的数据变化 一般使用 watch代替
watch可以监听某一个数据  数据更新的钩子会监听整个页面的数据变化

组件销毁阶段 beforeDestroy destroy 销毁
beforeDestroy 确定要销毁  还没有销毁

http的请求工具 ——axios
axios是市场占有率高 用法很好
支持Promise  支持在nodejs使用
通用写法
axios({
    method:"get/post/delete/put/patch",//请求类型
    url:'',//请求地址
    data:{},//请求体参数  body参数  get只有地址参数
    params:{} //地址参数  最终参数会拼接到url地址上
}).then(result=>{}).catch()

别名写法:
axios.get(url)
axios.post(url,data{})//data是请求体参数
axios.delete(url)
axios.put(url,data{})
axios.patch(url,data{})


$.ajax({
    
})


组件的ref属性和$nextTick
ref是获取真实的dom元素  组件的实例对象

先给组件标签一个ref属性
<counter-com ref='efg'

h1 ref='abc'
methods:{
    getRef(){
this.$refs.abc   //h1的dom元素
this.$refs.efg //获取组件的实例对象 得到其组件的this指向 可以使用其内部的属性和方法
}
}

$nextTick  vue的渲染是异步的
setTimeout setInterva ajax Promise.then.catch
先执行同步代码  等到主线程执行完毕 再去(按照到时顺序)执行任务对列的异步代码

数据更新之后  立刻获取dom结构  dom结构是上一次的
this.$nextTick(()=>{})//异步更新完成  执行这个函数确保异步更新已经完成

购物车的案例 json-server 讲一个json文件变成一个服务器 开启一个服务 提供一个接口

restful接口的规范--业界通用的规范
同样的地址  不同类型处理不同的业务
用户业务--新增-删除-更新-查询
查询用户:查询用户的列表  和单个用户的详情
get-/user 查询用户的列表  /user/:id 动态参数  查询单个用户的详情
post-/user 请求体参数 新增用户
put-/user/:id 请求体参数  更新用户
delete/user/:id  删除用户


获取购物车的数据
axios.defaults.baseURL=''//配置基础地址  不用写地址的前缀
因为前缀是一样的
在created中获取数据
list:[],

created(){
    this.getGoodList()
}
methods:{
    getGoodList(){
    axios.get().then(result=>{
    this.list=result.data
}).catch()

}

}


day6:
1.购物车案例  父传子props  子传父 自定义事件
2.动态组件-<component :is='组件名称'></component>
多个不同的组件显示在一个位置

3.组件缓存
组件被缓存 没有被销毁  存放在虚拟dom中 销毁真实dom
用<keep-alive>标签包裹组件 就缓存虚拟dom  保存组件实例
组件只会创建一次 提示性能  created只执行一次
只有激活和休眠两个函数   activated() deactivated()

4.插槽  
占位:<slot></slot> 在组件中定义坑的位置

填补内容:<child> 填补内容</child>

匿名插槽  没有定义name名称的
<slot></slot>

具名插槽 
<slot name='before'></slot>
填补的时候需要指定名称  template不起任何作用 代表这是标签 
<child> <template v-slot:before  或者 slot='before'>123</template>   </child>

后备内容
没有人传入插槽内容的时候  后备内容显示
<slot>后备内容</slot>

作用域插槽
父组件传递插槽内容的时候  需要使用子组件的数据
1.在子组件传递出你想让父组件使用的数据
<slot a='1' b='2' :d='变量'></slot>
<slot name='after' a='1' b='2' :d='变量'></slot>

2.传递插槽内容时  获取变量
<child>
obj是传递出所有属性的几何
    <template v-slot:after='obj'  >
    template  slot='after' slot-scope='obj'
    <div>
        a:{{obj.a}}
        b:{{obj.b}}
    </div>
</template>
</child>
使用具名插槽的时候
<child>
    div slot='名字' slot-scope='变量名  //第一种语法
    <template v-slot:'名字'='变量名'  //第二种语法
</child>

自定义指令
开发者可以封装指令
局部注册  全局注册

export default{
    directive:[
    "focus":{
    //指令描述
    inserted(){
    此时表示此指令作用的dom元素已经被插入到页面上
    }
}
}
}
.sync 修饰符
子传父 子组件触发  父组件监听
.sync 子组件触发 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
要使用Vue框架模仿黑马程序员官网,你可以按照以下步骤进行操作: 1. 创建Vue实例:首先,在HTML文件中引入Vue.js库,并创建一个Vue实例。在实例中,你可以定义数据、方法和计算属性等。 2. 绑定数据和视图:使用Vue的数据绑定语法,将数据和视图进行绑定。你可以在HTML中使用双花括号{{}}来显示数据,也可以使用v-bind指令来绑定属性。 3. 创建组件:根据官网的结构,将页面拆分为多个组件。每个组件都有自己的模板、数据和方法。你可以使用Vue的组件系统来创建和注册组件。 4. 路由配置:使用Vue Router来配置页面的路由。你可以定义不同的路由路径和对应的组件,以实现页面之间的切换。 5. 状态管理:使用Vuex来管理应用的状态。你可以在Vuex中定义状态、mutations和actions等,以实现数据的共享和管理。 6. 样式设计:根据官网的样式,使用CSS来设计页面的样式。你可以使用Vue的样式绑定语法,将样式与数据进行绑定。 7. 响应式交互:根据官网的交互效果,使用Vue的指令和事件处理机制,实现页面的响应式交互。你可以使用v-on指令来监听事件,也可以使用v-if和v-for等指令来控制元素的显示和循环。 8. 发布部署:最后,将你的代码打包并发布到服务器上,以实现在浏览器中访问你的模仿官网。 下面是一个简单的示例代码,演示了如何使用Vue框架模仿黑马程序员官网: ```html <!DOCTYPE html> <html> <head> <title>模仿黑马程序员官网</title> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> </head> <body> <div id="app"> <header> <h1>{{ title }}</h1> </header> <nav> <ul> <li v-for="item in menu" :key="item.id">{{ item.name }}</li> </ul> </nav> <main> <router-view></router-view> </main> <footer> <p>{{ copyright }}</p> </footer> </div> <script> // 创建Vue实例 const app = new Vue({ el: '#app', data: { title: '模仿黑马程序员官网', menu: [ { id: 1, name: '首页' }, { id: 2, name: '课程' }, { id: 3, name: '讲师' }, { id: 4, name: '社区' }, { id: 5, name: '关于我们' } ], copyright: '版权所有 © 2021 黑马程序员' } }); </script> </body> </html> ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

fameless

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

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

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

打赏作者

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

抵扣说明:

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

余额充值