Vue [Day3]

Vue生命周期

生命周期四个阶段

生命周期函数(钩子函数)

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<script src="../vue.js"></script>
<link rel="stylesheet" href="../base.css">
<style>

</style>

<body>
    <div id="app">
        <h3>{{title}}</h3>
        <button @click="count++">+</button>
        {{count}}
        <button @click="count--">-</button>
    </div>
</body>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            count: 100,
            title: '计数器'
        },
        // 1.创建阶段(准备数据)
        beforeCreate() {
            console.log(' beforeCreate 响应式数据准备好之前');

        },
        created() {
            console.log(' created 响应式数据准备好之后');
            // 可以开始发送初始化渲染的请求了   this.数据名=请求回来的数据
        },

        // 2.挂载阶段(渲染模板)
        beforeMount() {
            console.log(' beforeMount 模板渲染之前');
        },
        mounted() {
            console.log(' mounted 模板渲染之后');
            // 可以开始操作dom
        },



    })
</script>

</html>

【案例】------ 小黑记账本

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<script src="../vue.js"></script>
<link rel="stylesheet" href="../base.css">
<style>
    #app {
        margin: 50px 50px;
        display: flex;
        width: 900px;
        height: 300px;
    }

    .left {
        flex: 1;
    }

    .right {
        flex: 1;
        background-color: #864343;
    }

    table {
        width: 400px;
        margin-top: 20px;
        text-align: center;
        border: 1px solid black;
        border-spacing: 0;
    }

    td,
    th {
        border-bottom: 1px solid black;
    }

    /* 超过500元 高亮 */
    .red {
        color: red;
    }
</style>

<body>
    <div id="app">
        <div class="left">
            <div class="head">
                <!-- 不用加{{}} v-model="{{name}}" 这样写是错的-->
                <input v-model.trim="name" type="text" placeholder="消费名称">
                <input v-model="price" type="text" placeholder="消费价格">
                <button @click="add"> 添加账单</button>
            </div>

            <!-- 表单;账单主体 -->
            <table>
                <thead>
                    <tr>
                        <th>编号</th>
                        <th>消费名称</th>
                        <th>消费价格</th>
                        <th>操作</th>
                    </tr>
                </thead>
                <tbody v-if="list.length>0">
                    <tr v-for="(item,index) in list" :key="item.id">
                        <td>{{index+1}}</td>
                        <td>{{item.name}}</td>
                        <td :class="{red:item.price>500}">{{item.price.toFixed(2)}}</td>
                        <td><a @click="del(item.id)" href="#" style="color:blue">删除</a></td>
                    </tr>
                </tbody>

                <tbody v-else>
                    <tr>
                        <td colspan="4">无</td>
                    </tr>
                </tbody>

                <tfoot>
                    <tr>
                        <td colspan="4">总计:{{totalPrice.toFixed(2)}}</td>
                    </tr>
                </tfoot>
            </table>
        </div>
        <div class="right"></div>
    </div>
</body>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.0/dist/echarts.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
    /**
     * 接口文档地址:
     * https://www.apifox.cn/apidoc/shared-24459455-ebb1-4fdc-8df8-0aff8dc317a8/api-53371058
     * 
     * 功能需求:
       * 1. 基本渲染
       *    (1) 立刻发送请求获取数据 created
       *    (2) 拿到数据,存到data的响应式数据中
       *    (3) 结合数据,进行渲染 v-for
       *    (4) 消费统计 => 计算属性
       * 2. 添加功能
       *    (1) 收集表单数据 v-model
       *    (2) 给添加按钮注册点击事件,发送添加请求
       *    (3) 需要重新渲染 只是后台数据更新,所以要再渲染一边
       * 3. 删除功能
       *    (1) 注册点击事件,传参传 id
       *    (2) 根据 id 发送删除请求
       *    (3) 需要重新渲染
       * 4. 饼图渲染
       *    (1) 初始化一个饼图 echarts.init(dom)  mounted钩子实现
       *    (2) 根据数据实时更新饼图 echarts.setOption({ ... })
     */

    const app = new Vue({
        el: '#app',
        data: {

            // 亲爱的,这次的数据不是写死的,而是从接口拿的
            // list: [
            //     { id: 1, name: '衣服', price: 130 },
            //     { id: 2, name: '零食', price: 30 },
            //     { id: 3, name: '娱乐', price: 90 },
            // ]

            // 所以,直接定义就行了,具体的值后面赋
            list: [],
            name: '',
            price: ''
        },
        created() {
            // const res = await axios.get('https://applet-base-api-t.itheima.net/bill', {
            //     params: {
            //         creator: 'slx'
            //     }
            // })
            // // console.log(res.data);
            // this.list = res.data.data

            // 一进页面就调用
            this.getList()
        },
        mounted() {
            this.myChart = echarts.init(document.querySelector('.right'))
            this.myChart.setOption({
                title: {
                    text: '消费列表',

                    left: 'center'
                },
                // 提示框
                tooltip: {
                    trigger: 'item'
                },

                // 图例
                legend: {
                    orient: 'vertical',
                    left: 'left'
                },
                series: [
                    {
                        name: '消费账单',
                        type: 'pie',
                        radius: '50%',
                        data: [
                            { value: 1048, name: 'Search Engine' },
                            { value: 735, name: 'Direct' },
                            { value: 580, name: 'Email' },
                            { value: 484, name: 'Union Ads' },
                            { value: 300, name: 'Video Ads' }
                        ],
                        emphasis: {
                            itemStyle: {
                                shadowBlur: 10,
                                shadowOffsetX: 0,
                                shadowColor: 'rgba(0, 0, 0, 0.5)'
                            }
                        }
                    }
                ]
            })
        },



        computed: {
            totalPrice() {
                return this.list.reduce((sum, item) => sum += item.price, 0)
            }
        },

        methods: {
            // 封装成函数,每次都要渲染
            async getList() {
                const res = await axios.get('https://applet-base-api-t.itheima.net/bill', {
                    params: {
                        creator: 'slx'
                    }
                })
                // console.log(res.data);
                this.list = res.data.data
                this.myChart.setOption({
                    series: [
                        {

                            // data: [
                            // { value: 1048, name: 'Search Engine' },
                            // { value: 735, name: 'Direct' },
                            // ],

                            //                         ()必须加,不然会以为是代码段
                            data: this.list.map(item => ({ value: item.price, name: item.name }))
                        }
                    ]
                })
            },
            async add() {
                // if (parseFloat(this.price) == 'NaN') {
                //     console.log('NAN!!!!!');
                // 好吧,小知识点不会,在JavaScript中,NaN是一个特殊的值,表示不是一个有效的数字。然而,NaN与任何其他值(包括NaN本身)进行相等比较时都会返回false。所以,使用==或===运算符将parseFloat(this.price)与字符串'NaN'进行比较,结果永远是false。
                // 为了判断parseFloat(this.price)是否为NaN,你可以使用全局的isNaN()函数来进行判断。
                // }

                if (!this.name) {
                    alter('请输入消费名称')
                    return
                }

                // 我觉得他这个不全,要是用户输入12.396.353.3也还是不报错,所以就自己手动加判断了
                // if (typeof this.price != 'number') {
                //     alert('请输入正确的数字')
                //     return
                // }

                let ch = '.'
                let count = this.price.split(ch).length - 1;
                if (count > 1) {
                    alert('请输入正确的数字')
                    return
                }
                if (isNaN(parseFloat(this.price))) {
                    console.log('NAN');
                    alert('请输入正确的数字')
                    return
                }
                else {
                    this.price = parseFloat(this.price)

                }
                const res = await axios.post('https://applet-base-api-t.itheima.net/bill', {
                    // data: {   post不用写这个
                    creator: 'slx',
                    name: this.name,
                    price: this.price
                    // }
                })
                console.log(res);
                this.getList()

                // 输入后清空
                this.name = ''
                this.price = ''
            },

            async del(tt) {
                // 注意这个的写法,``  $
                const res = await axios.delete(`https://applet-base-api-t.itheima.net/bill/${tt}`)
                // console.log(res);
                this.getList()
            }

        },




    }) 
</script>

</html>

工程化开发 & 脚手架 Vue CLI

脚手架目录文件介绍 & 项目运行流程

main.js

js 复制代码
// 文件核心作用:导入App.vue,基于App.vue创建结构渲染index.html
// 1. 导入 Vue 核心包
import Vue from 'vue'

// 2. 导入 App.vue 根组件
import App from './App.vue'

// 提示:当前处于什么环境 (生产环境 / 开发环境)
Vue.config.productionTip = false

// 3. Vue实例化,提供render方法 → 基于App.vue创建结构渲染index.html
new Vue({
  // el: '#app', 作用:和$mount('选择器')作用一致,用于指定Vue所管理容器
  // render: h => h(App),
  render: (createElement) => {
    // 基于App创建元素结构
    return createElement(App)
  }
}).$mount('#app')

组件化开发 & 根组件



App.vue

js 复制代码
<template>
  <div class="App">
    <div class="box" @click="fn"></div>
  </div>
</template>

<script>
// 导出的是当前组件的配置项
// 里面可以提供 data(特殊) methods computed watch 生命周期八大钩子
export default {
  created () {
    console.log('我是created')
  },
  methods: {
    fn () {
      alert('你好')
    }
  }
}
</script>

<style lang="less">
/* 让style支持less
   1. 给style加上 lang="less"
   2. 安装依赖包 less less-loader
      yarn add less less-loader -D (开发依赖)
*/
.App {
  width: 400px;
  height: 400px;
  background-color: pink;
  .box {
    width: 100px;
    height: 100px;
    background-color: skyblue;
  }
}
</style>

普通组件的注册使用

局部注册

App.vue

js 复制代码
<template>
  <div class="hm-header">
    我是hm-header
  </div>
</template>

<script>
export default {

}
</script>

<style>
.hm-header{
    height: 100px;
    line-height: 100px;
    text-align: center;
    font-size: 30px;
    background-color: #cdcf48;
}
</style>

components/HmFooter.vue

js 复制代码
<template>
  <div class="App">

<!-- 使用,直接当成html标签使用 -->
<!-- 组件命名规范,大驼峰命名法 -->


<!-- 头部组件 -->
<HmHeader></HmHeader>  

<!-- 主体组件 -->
<HmMain></HmMain>

<!-- 底部组件 -->
<HmFooter></HmFooter>

  </div>
</template>

<script>
// 导入
import HmFooter from './components/HmFooter.vue';
import HmHeader from './components/HmHeader.vue';
import HmMain from './components/HmMain.vue';

export default {

  // 局部注册
components:{
  // '组件名':'组件对象
  
  HmHeader:HmHeader,
  HmFooter,// 同名可简写
  HmMain,
}
}
</script>

<style>
.App{
  width: 600px;
  height: 700px;
  background-color:rgb(0, 234, 255);
  padding: 20px;
  margin: 0 auto;
}
</style>

全局注册

HmButton.vue

js 复制代码
<template>
  <button class=".hm-button">通用按钮</button>
</template>

<script>
export default {

}
</script>

<style>
.hm-button{
    height: 50px;
    line-height: 50px;
    padding: 0 20px;
    background-color: #ca2a50;
    border-radius: 5px;
}
</style>

main.js

js 复制代码
// 文件核心作用:导入App.vue,基于App.vue创建结构渲染index.html
import Vue from 'vue'
import App from './App.vue'

// 1.导入的代码,都写在上面,书写规范
import HmButton from './components/HmButton'
Vue.config.productionTip = false

// 2.进行全局注册
// Vue.component(组件名,组件注册)
Vue.component('HmButton', HmButton)


new Vue({

  render: (createElement) => {

    return createElement(App)
  }
}).$mount('#app')

HmFooter.vue

js 复制代码
<template>
    <div class="hm-footer">
      我是hm-footer

      <!-- 直接用 -->
      <HmButton></HmButton>

    </div>
  </template>
  
  <script>
  export default {
  
  }
  </script>
  
  <style>
  .hm-footer{
      height: 100px;
      line-height: 100px;
      text-align: center;
      font-size: 30px;
      background-color: #6848cf;
  }
  </style>

两种注册方式总结

【案例】------ 小兔鲜 组件拆分

相关推荐
Martin -Tang21 分钟前
vite和webpack的区别
前端·webpack·node.js·vite
迷途小码农零零发22 分钟前
解锁微前端的优秀库
前端
王解1 小时前
webpack loader全解析,从入门到精通(10)
前端·webpack·node.js
老码沉思录1 小时前
写给初学者的React Native 全栈开发实战班
javascript·react native·react.js
我不当帕鲁谁当帕鲁1 小时前
arcgis for js实现FeatureLayer图层弹窗展示所有field字段
前端·javascript·arcgis
那一抹阳光多灿烂1 小时前
工程化实战内功修炼测试题
前端·javascript
放逐者-保持本心,方可放逐2 小时前
微信小程序=》基础=》常见问题=》性能总结
前端·微信小程序·小程序·前端框架
毋若成4 小时前
前端三大组件之CSS,三大选择器,游戏网页仿写
前端·css
红中马喽4 小时前
JS学习日记(webAPI—DOM)
开发语言·前端·javascript·笔记·vscode·学习
Black蜡笔小新5 小时前
网页直播/点播播放器EasyPlayer.js播放器OffscreenCanvas这个特性是否需要特殊的环境和硬件支持
前端·javascript·html