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 CLI (vuejs.org)
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组件中的样式会全局生效,因此很容易造成多个组件之间样式冲突的问题
主要原因:
- 单页面应用程序中,所有组件的DOM结构,都是基于唯一的index.html页面进行呈现的
- 每个组件中的样式,都会影响整个index.html页面中的DOM元素
解决方案:1.给每个vue子组件style样式中添加scoped,其本质就是给每个标签添加一个独一无二的属性
2.当使用第三方组件库的时候,如果修改第三方组件默认样式,则需要用到/deep/
-
-
-
-
- 由于给vue子组件的样式中添加了scoped,需要修改第三方组件的默认样式时,如果直接在该子组件中修改,选择器选中的是带有scoped添加的属性的标签,但第三方组件的标签不包含该属性所以筛选不到。因此,我们需要在样式选择器前面添加/deep/,这样在筛选时会变成在拥有scoped添加的属性下查询该制定个标签,这样就可以查询到了。
-
-
-

浙公网安备 33010602011771号