Vue-3

(一)过滤器的基本用法

  过滤器(Filters)是vue为开发者提供的功能,常用于文本的格式化。过滤器可用于两个地方:插值表达式、v-bind属性绑定

  过滤器应该被添加在javascript表达式的尾部,由“管道符”进行调用

  • 过滤器的基本使用
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
    </head>
    <body>
        <div id="app">
            <!-- 将首字母改为大写 -->
            <p>message的值是: {{message | capitalize}}</p>
        </div>
        <script src="js/v2.6.10/vue.js"></script>
        <script>
            const vm = new Vue({
                el: '#app',
                data: {
                    message: 'hello vue.js'
                },
                // 过滤器函数必须被定义到filters节点之下
                filters:{
                    //形参里面的值就是调用时“管道符”|前面的值
                    capitalize(message){
                        console.log(message);
                        const first = message.charAt(0).toUpperCase();
                        //强调过滤器中一定要一个返回值
                        return first+message.substr(1,);
                    }
                }
            })
        </script>
    </body>
</html>
  • 私有过滤和全局过滤

    在filters节点下的过滤器,成为‘私有过滤器’,因为它只能在当前vm实例所控制的el区域内使用,如果希望在多个vue实例之间共享过滤器,可以创建全局过滤器

    • 全局过滤器
      • 如果全局过滤器和私有过滤器冲突,按照就近原则,优先调用自己的过滤器、
      • 全局过滤器必须写在自己的作用域的vm实例之前
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
    </head>
    <body>
        <div id="app">
            <p>message的值是: {{message | capitalize}}</p>
        </div>
        <div id="name">
            <p>name的值是: {{name | capitalize}}</p>
        </div>
        <script src="js/v2.6.10/vue.js"></script>
        <script>
            //全局过滤器-独立于每个vm实例之外的
            //Vue.filter()方法接收两个参数
            //第一个参数,是全局过滤器的名字
            //第二个参数,是全局过滤器的“处理函数”
            Vue.filter('capitalize',(str)=>{
                const first = str.charAt(0).toUpperCase();
                return first+str.slice(1);
            })
            
            const vm = new Vue({
                el: '#app',
                data: {
                    message: 'hello vue.js'
                }
            })
            const vm1 = new Vue({
                el: '#name',
                data: {
                    name: 'baekhyun'
                }
            })
        </script>
    </body>
</html>
    • 拓展:上个案例处理时间,可以使用day.js库
<script src="https://cdn.bootcdn.net/ajax/libs/dayjs/1.4.1/dayjs.min.js"></script>
    • 连续调用多个过滤器:过滤器可以串联的进行调用,前一个过滤器的返回值作为后一个过滤器的参数
    • 过滤器可以接受参数
      • 第一个参数永远是管道符前面待处理的值
      • 第二个参数开始,才是调用过滤器时传递过来的参数
    • 过滤器的兼容性:过滤器仅在vue 2.x和1.x中受支持,在vue 3.x的版本中删除类过滤器的相关功能

(二)侦听器

  watch侦听器运行开发者监视数据的变化,从而针对数据的变化做特定的操作

  • 侦听器基本的语法格式
     <div class="app">
            <input type="text" v-model="username" />
        </div>
        <script src="js/v2.6.10/vue.js"></script>
        <script>
            const vm = new Vue({
                el: '.app',
                data: {username: 'baekhyun'},
                //所有的侦听器都应该被定义到watch节点下
                watch: {
                    //侦听器本质上是一个函数,要侦听哪一个数据的变化,就把数据名作为方法名,新值在前,旧值在后
                    username(newVal,oldVal){
                        //newVal是变化之后的新值
                        //oldVal是变化之后的旧值
                        console.log(newVal,oldVal);
                    }
                }
            })
        </script>
  •  判断用户名是否被占用
    • html
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
    </head>
    <body>
        <div class="app">
            <input type="text" v-model="username" />
            <div class="notice"></div>
        </div>
        <script src="js/v2.6.10/vue.js"></script>
        <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
        <script>
            const vm = new Vue({
                el: '.app',
                data: {username: ''},
                //所有的侦听器都应该被定义到watch节点下
                watch: {
                    //侦听器本质上是一个函数,要侦听哪一个数据的变化,就把数据名作为方法名
                    username(newVal,oldVal){
                        //newVal是变化之后的新值
                        //oldVal是变化之后的旧值
                        //1.调用axios中的ajax请求,判断newVal是否被占用
                        axios.defaults.baseURL = "http://127.0.0.1:8000";
                        axios.get("/info",{
                            params:{
                                name: newVal
                            }
                        }).then(value=>{
                            const notice = document.querySelector(".notice");
                            notice.innerHTML = value.data.message;
                            if(value.data.flag){
                                notice.style.color = 'green';
                            }else{
                                notice.style.color = 'red';
                            }
                        })
                        
                    }
                }
            })
        </script>
    </body>
</html>
    • js
//1.引入express
const express = require("express");
//2.创建应用对象
const app = express();
app.all('/info',(request,response)=>{
    response.setHeader("Access-Control-Allow-Origin","*");
    response.setHeader("Access-Control-Allow-Headers","*");
    const names = ['tom','jerry','alice','bob'];
    const name = request.query.name;
    if(names.includes(name)){
        const obj = {
            flag: false,
            message: 'Sorry, the name is already in use'
        }
        response.send(JSON.stringify(obj));
    }else{
        const obj = {
            flag: true,
            message: 'Lucky, the name is not in use'
        }
        response.send(JSON.stringify(obj));
    }
})
app.listen(8000,()=>{
    console.log("正在监听8000端口");
})
  • 侦听器的格式
    • 方法格式的侦听器
      • 缺点:无法在刚进入页面的时候,自动触发
      • 缺点:如果侦听的是一个对象,如果对象中的属性发生了变化,不会触发侦听器
    • 对象格式的侦听器
      • 好处:可以通过immediate选项,让侦听器自动触发
      • 好处:可以通过deep选项,让侦听器深度监听对象中每个属性的变化
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
    </head>
    <body>
        <div class="app">
            <input type="text" v-model.lazy="info.username" />
            <div class="notice"></div>
        </div>
        <script src="js/v2.6.10/vue.js"></script>
        <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
        <script>
            const vm = new Vue({
                el: '.app',
                data: {
                    info: {
                            username: 'baekhyun'
                    }
                },
                watch: {
                    //定义对象格式的侦听器
                    info: {
                        //侦听器的处理函数,如果侦听的是对象的子属性的变化,则要但单引号:'info.username',与deep二选一
                        handler(newVal){
                            axios.defaults.baseURL = "http://127.0.0.1:8000";
                            axios.get("/info",{
                                params:{
                                    name: newVal.username
                                }
                            }).then(value=>{
                                const notice = document.querySelector(".notice");
                                notice.innerHTML = value.data.message;
                                if(value.data.flag){
                                    notice.style.color = 'green';
                                }else{
                                    notice.style.color = 'red';
                                }
                            })
                        },
                        //immediate选项的默认值是false
                        //它的作用是控制侦听器是否自动触发
                        immediate: true,
                        //开启深度监听,只要对象中有任何一个属性变化了,就会触发“对象的侦听器”
                        deep: true
                    }
                }
            })
        </script>
    </body>
</html>

(三)计算属性

  计算属性指的是通过一系列的运算之后,最终得到的一个属性值

  这个动态计算出来的属性值可以被模板结构或methods方法使用

  • 特点
    • 定义的时候,要被定义为方法
    • 在使用计算属性的时候,当普通的属性使用即可
  • 好处
    • 实现了代码复用
    • 只要计算属性中依赖的数据源变化了,则计算属性会重新求值
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <style type="text/css">
            .pic {
                width: 200px;
                height: 200px;
                margin-left: 10px;    
            }
            
            input {
                margin-left: 10px;
            }
        </style>
    </head>
    <body>
        <div class="app">
            R:<input type="number" class="R" v-model="R"/><br>
            G:<input type="number" class="G" v-model="G"/><br>
            B:<input type="number" class="B" v-model="B"/>
            <hr >
            <!-- 专门用户呈现颜色的div盒子 -->
            <!-- 在属性身上 :等于v-bind,它的值是一个{}样式对象 -->
            <!-- 当前样式对象中只包含backgroundColor背景颜色 -->
            <div class="pic" :style="{backgroundColor: rgb}">{{rgb}}</div>
            <input type="button" value="按钮" @click="show"/>
        </div>
        <script src="js/v2.6.10/vue.js"></script>
        <script>
            const vm = new Vue({
                el: '.app',
                data: {
                    R: 0,
                    G: 0,
                    B: 0
                },
                methods:{
                    show(){
                        console.log(this.rgb)
                    }
                },
                //所有的计算属性,都要定义到computed节点之下
                //计算属性在定义的时候要定义为方法格式
                computed:{
                    //rgb作为一个计算属性,被定义为了方法格式
                    //最终,在这个方法中,要返回一个生成好的rgb(r,g,b)字符串
                    rgb(){
                        return `rgb(${this.R},${this.G},${this.B})`;
                    }
                }
            })
        </script>
    </body>
</html>

 (四)axios

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
    </head>
    <body>
        <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
        <script>
            //如果调用某个方法的返回值是Promise实例,则前面可以添加await
            //await只能用在被async修饰的方法中,以此可以方便的使用解构
            //解构赋值的时候使用:进行重命名
            // 1.使用axios之后,使用async和await进行简化
            // 2.使用解构赋值,从axios封装的大对象中,把data属性提取出来
            // 3.把解构出来的data属性,使用:进行重命名,一般重命名为{data:res}
            const res = axios({
                //请求方式
                // method: 'GET',
                method: 'POST',
                //请求路径
                url: 'http://127.0.0.1:8000/hello',
                //查询URL中的查询参数
                params:{},
                //请求体参数
                data: {}
            })
            console.log(res);
            console.log(res.then(data=>console.log(data)));
        </script>
    </body>
</html>

(五)vue-cli

  • 单页面应用程序SPA(Single page Application)

     指的是一个web网站中只有唯一的一个HTML页面,所有的功能与交互都在这唯一的一个页面内完成

    vue-cli是vue.js开发的标准工具。它简化了程序员基于webpack创建工程化的Vue项目的过程,是npm上的一个全局包

    • 安装和使用
      • npm install -g @vue/cli:通过 vue -V进行检测看是否有vue-cli的版本号
      • 基于vue-cli快速生成工程化的Vue项目:vue create 项目名称 
    • vue项目中src的目录构成
      • assets文件夹:存放项目中用到的静态资源文件,例如css样式表、图片资源
      • components文件夹:程序员封装的一些可复用的组件,都要放到components目录下
      • main.js:是项目入口文件,整个项目的运行,要先执行main.js
      • App.vue:是项目的根组件
    • vue项目的执行流程

        在工程化的项目中,vue要做的事情很单纯:通过main.js把App.vue渲染到index.html的指定区域中

    • mian.js解析
//导入Vue这个包,得到Vue构造函数
import Vue from 'vue'
//导入App.vue根组件,将来要把App.vue渲染到html页面中
import App from './App.vue'

Vue.config.productionTip = false
//创建Vue实例对象
new Vue({
    //el: '#app',
    //把render函数指定的组件渲染到html页面中
  render: h => h(App),
}).$mount('#app')

//Vue实例的$mount方法,作用和el属性完全一样

(六)vue组件化开发

  组件化的开发指的是:根据封装的思想,把页面上可重用的UI结构封装为组件,从而方便项目的开发和维护

  vue是一个支持组件化开发的前端框架

  vue中规定:组件的后缀名是.vue,之前接触到的App.vue本质上就是一个vue的组件

  • vue组件的三个组成部分
    • template->组件的模板结构
    • script->组件的javaScript行为
    • style->组建的样式
<template>
    <!-- template中只能由一个根元素 -->
    <div class="box">
        <h4>{{username}}</h4>
        <h3>{{sex}}</h3>
        <button @click="changeName">点我一下</button>
    </div>
</template>
<script>
    //默认导出,这是固定写法
export default{
    //data数据源
    //注意:组件里面的data不能指向对象,应该是一个函数
    data(){
        //这个return出去的{}中,可以定义数据
        return {
            username: 'BAEKHYUN',
            sex: 'man'
        }
    },
    methods:{
        changeName(){
            //在组件中,this表示当前组件的实例对象实例
            this.username = 'BBH';
        }
    },
    //当前组件中的侦听器
    watch:{},
    //当前组件中的计算属性
    computed:{},
    //当前组件中的过滤器
    filters:{}
}
</script>
<style>
    /* 在style中如果不添加lang='less'默认是css语法 */
    h4 {
        color: pink;
    }
</style>
  • 组件之间的父子关系

    组件在被封装好之后,彼此之间是相互独立的,不存在父子关系

    在使用组件的时候,根据彼此的嵌套关系,形成父子关系

    • 使用@符号代表src根目录
//webpack.config.js
module.exports = {
  resovle: {
      alias:{
          @: path.join(__dirname,"./src");
      }
  }
}
    • 使用组件的三个步骤
      • 使用import语法导入需要的组件
      • 使用components节点注册组件
      • 以标签形式使用刚才注册的组件
<template>
    <!-- template中只能由一个根元素 -->
    <div class="box">
        这是一个App根组件
        <!-- 3.以标签形式使用组件 -->
        <Left></Left>
        <Right></Right>
    </div>
</template>
<script>
    //1.导入要使用的Left和Right组件
    import Left from '@/components/Left.vue'
    import Right from '@/components/Right.vue'
    //默认导出,这是固定写法
export default{//2.组件注册
    components: {
        'Left': Left,
        'Right': Right
    }
}
</script>
<style>
    /* 在style中如果不添加lang='less'默认是css语法 */
    .box {
        height: 200px;
        background-color: orange;
    }
</style>
  • HTML配置@路径提示插件

    https://ext.dcloud.net.cn/plugin?id=4734

  •  使用Vue.component全局注册组件
    • 使用components注册的是私有组件
    • 注册全局组件

      在vue项目main.js入口文件中,通过Vue.component()方法,可以注册全局组件

//导入Vue这个包,得到Vue构造函数
import Vue from 'vue'
//导入App.vue根组件,将来要把App.vue渲染到html页面中
import App from './App.vue'
//1.导入需要被注册的组件
import Count from '@/components/Count.vue'
//参数1:字符串格式,表示组件的"注册名称"
//参数2:需要被全局注册的那个组件
Vue.component('Count',Count);
Vue.config.productionTip = false
//创建Vue实例对象
new Vue({
    //el: '#app',
    //把render函数指定的组件渲染到html页面中
  render: h => h(App),
}).$mount('#app')

//Vue实例的$mount方法,作用和el属性完全一样
  •  组件里的props

    props是组件的自定义属性,在封装通用组件的时候,合理的使用props,可以极大地提高组件的复用性

<template>
    <div>
        <h5>Count组件</h5>
        <p>count的值是:{{count}}</p>
        <!-- 当代码方法只有一行代码时,可以直接写在引号内 -->
        <!-- vue规定:组件中封装的自定义属性时只读的,程序员不能直接修改props的值,否则会报错 -->
        <button @click="count++">+1</button>
    </div>
</template>

<script>
    export default {
        //props是自定义属性,允许使用者通过自定义属性,为当前组件指定初始值
        //自定义属性的名字是封装自定义的
        //props中的数据,可以直接在模板结构中被使用
        props:['init'],
        data(){
            return {
                count: this.init
            }
        }
    }
</script>

<style lang="less">
    
</style>
    • props的default默认值
     //在声明自定义属性时,可以通过default来定义属性的默认值
        //自定义属性A: {/*配置选项*/}
        props: {
            init: {
                //如果外界使用Count组件的时候,没有传递init属性,则默认值生效
                default: 0
            }
        },
    • props的type属性
    props: {
            init: {
                //用default属性定义属性的默认值
                default: 0,
                //使用type属性定义属性的值的类型
                //如果传递过来的值不符合此类型,则会在终端报错
                type: Number
            }
        },
    • props的required必填项
    props: {
            init: {
                default: 0,
                type: Number,
                //为必填项,必填项校验,检验视为有传值,和默认值没有关系
                required: true
            }
        },
  • 组件之间的样式冲突

    默认情况下,写在vue组件中的样式会全局生效,因此很容易造成多个组件之间样式冲突的问题

    主要原因:

      1. 单页面应用程序中,所有组件的DOM结构,都是基于唯一的index.html页面进行呈现的
      2. 每个组件中的样式,都会影响整个index.html页面中的DOM元素

    解决方案:1.给每个vue子组件style样式中添加scoped,其本质就是给每个标签添加一个独一无二的属性

         2.当使用第三方组件库的时候,如果修改第三方组件默认样式,则需要用到/deep/

          • 由于给vue子组件的样式中添加了scoped,需要修改第三方组件的默认样式时,如果直接在该子组件中修改,选择器选中的是带有scoped添加的属性的标签,但第三方组件的标签不包含该属性所以筛选不到。因此,我们需要在样式选择器前面添加/deep/,这样在筛选时会变成在拥有scoped添加的属性下查询该制定个标签,这样就可以查询到了。
posted @ 2022-05-03 18:38  Miraitowa56  阅读(98)  评论(0)    收藏  举报