框架技术 ---- SPA和Vue的组件化开发

Vue框架


Vue3基础:组件化开发


前面简单介绍了vue的两个特性:数据驱动视图,双向数据绑定; 分别就是使用插值表达式或者v-model来操作,并且分享了vue2的过滤器,在vue3中直接采用方法调用或者计算属性的方式来操作即可;还有各种事件修饰符,v-model修饰符和按键修饰符

而页面的一

单页面应用程序SPA

single page application 单页面应用程序SPA,指的是一个web网站只有唯一的一个HTML页面,所有的功能和交互都在这唯一的一个页面完成;单页面应用程序将所有的功能局限在一个web页面中,只是在该页面初始化的时候加载响应的资源(HTML,JavaScript和CSS)

一旦页面加载完成了,SPA不会因为用户的操作而进行页面的重新加载或者跳转,而是利用JavaScript动态变换HTML的内容,实现页面与用户的交互【只有一个html网页】

  • 良好的交互体验

    • SPA的内容改变不需要重新加载整个页面(全局刷新)
    • 获取的数据通过AJAX异步实现
    • 没有页面之间的跳转,不会出现白屏
  • 前后端分离

    • 后端专注于API接口,更容易实现API接口的复用
    • 前传专注于页面的渲染,有利于前端工程化
  • 减轻服务器压力

    • 服务器只提供数据,不负责页面的合成和逻辑的处理,吞吐能力提高

SPA缺点

  • 首屏加载慢
    • 路由懒加载, 代码压缩,CDN加速,网络传输压缩
  • 不利于SEO(搜索优化)Search Engine Optimization
    • 可以使用SSR服务器端渲染

上面分析了这么多SPA项目的优缺点,那么如何创建一个SPA项目呢? 这里提供两种方案

  1. 基于Vite创建SPA项目 :只是支持Vue3.x, 不是基于webpack,运行速度快,功能小而巧,不建议企业开发使用 -----> 会慢慢变强
  2. 基于vue-cli创建 : 都支持,基于webpack,运行速度较慢,功能大而全,建议企业开发的时候使用【高版本变为了@vue】

Vite基本使用

Vite仅支持vue3.x,想要使用vite来快速建立一个vue项目,可以运行如下命令

npm init vite-app XXX     //这里建议使用英文

cd  XXXX     //打开项目

npm  install  //下载相关的依赖包

npm run dev   //执行dev脚本,打包运行程序

创建项目之后装包,npm run dev就可以将项目给跑起来

PS D:\Vueprogramm> npm init vite-app vueTest
Need to install the following packages:
  create-vite-app
Ok to proceed? (y)
npm WARN deprecated create-vite-app@1.21.0: create-vite-app has been deprecated. run `npm init @vitejs/app` or `yarn create @vitejs/app` instead.
Scaffolding project in D:\Vueprogramm\vueTest...

Done. Now run:

  cd vueTest
  npm install (or `yarn`)
  npm run dev (or `yarn dev`)

PS D:\Vueprogramm> cd vueTest
PS D:\Vueprogramm\vueTest> npm install

added 285 packages in 1m
PS D:\Vueprogramm\vueTest> npm run dev

> vueTest@0.0.0 dev
> vite

[vite] Optimizable dependencies detected:
vue

  Dev server running at:
  > Network:  http://192.*.56.1:3000/
  > Network:  http://10.*.206.29:3000/
  > Local:    http://localhost:3000/

这里成功将项目在网页上运行,打开地址访问即可

请添加图片描述

项目目录结构

使用HBudilerX打开项目

  • node_modules : 第三方的依赖包
  • public : 公共的静态资源目录 ----- 页面导航上面的小图标就放在这里
<link rel="icon" href="/cfeng.ico" /> <!-- 使用link rel为图标icon,加上href就可以显示 -->
这里的ico的位置一定是在public下面,也就是是公共的资源; 所以普通的项目如果不处理是没有小图标的
  • src : 项目的源代码目录( 开发者写的所有的代码都要放在这个目录下)
    • assets : 存放项目的所有的静态资源文件(.css、.less)等
    • components : 存放项目中所有的自定义组件
    • App.vue : 项目的根组件
    • index.css : 全局样式表文件
    • main.js : 整个项目的打包文件的入口 【之前的webpack类似的index.js】
  • .gitigonore : Git的忽略文件
  • index.html : SPA单页面应用程序的唯一的HTML页面
  • package.json 项目的包管理配置文件

vite项目的运行流程

在工程化的项目中,vue所发挥的功能很easy : 通过main.js将App.vue渲染到index.html的指定区域中

其中:

  • App.vue用来编写待渲染的模板结构
<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <HelloWorld msg="Hello Vue 3.0 + Vite" />
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'App',
  components: {
    HelloWorld
  }
}
</script>

//所有的模板文件都要使用template标签来定义,模板文件中的内容就是之后会通过main.js将其放入到index.html的控制的el区域中
  • index.html需要预留一个el区域【被vue对象控制】
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <link rel="icon" href="/cfeng.ico" /> <!-- 使用link rel为图标icon,加上href就可以显示 -->
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Vite App</title>
</head>
<body>
  <div id="app"></div>
  <script type="module" src="/src/main.js"></script>
</body>
</html>

<!-- 这里可以明显看到预留了一个被vue控制的div -->
  • main.js把App.vue渲染到index.html的el区域中

vue3.x的vue对象的创建和2.x不同,这点在之前已经分析过,

  1. 从vue中按需导入createApp函数【函数作用: 创建vue的SPA实例】单页面应用程序
  2. 导入待渲染的App组件
  3. 调用那个createApp()函数,返回值为spa实例,【前面说的vue对象:happy:】,用常量spa_app接收,同时把App组件作为参数传递给create函数,表示将App渲染到el区域
  4. 调用spa_app实例的mout方法,指定vue实际控制的区域
//这里就是之前我们手动写的script脚本
//导入createApp函数,创建spa实例
import { createApp } from 'vue'
//导入待渲染的App组件
import App from './App.vue'
//导入样式表模块,这里应该使用的loader
import './index.css'

//创建实例并渲染APP到指定的el区域
createApp(App).mount('#app')

/*
 之前没有定义常量接收spa实例,直接Vue.createApp(),并且没有接收组件来渲染
*/

组件化开发思想

组件化开发: 根据封装的思想,把页面上可以重用的部分封装为组件,从而方便项目的开发和维护【比如把轮播图封装为一个组件,需要用到时候就行】 — ES6模块化; 比如http://www.ibootstrap.cn/展示的效果就是组件化的思想

组件化开发的好处:

  • 提高了前端代码的复用性和灵活型
  • 提升了代码的开发效率和后期的可维护性

Vue中的组件化开发
vue是一个支持组件化开发的框架,vue中组件的后缀名为.vue,App.vue就是一个根组件

vue组件构成

每一个.vue的组件都是3个部分构成,分别是:

  • template -> 组件的模板结构
  • script -> 组件的JavaScript行为
  • style -> 组件的样式

每一个组件必须含有template模板结构,但是script行为和style样式是可选的,如果不需要美化,就可以省略

template结点

vue规定 : 每个组件对应的模板结构,都需要定义到< template> 结点中

<template>
	<!-- 当前组件的DOM结构,需要定义到template标签的内容 -->
</template>

注意: template 是vue提供的容器标签,只是起到包裹性质的作用, 不会被渲染成真正的DOM元素!!【template标签只是一个包裹作用,不是DOM的标签】 也就是只要通过main.js渲染到el区域中才会生效

但是在template结点中,支持使用之前的vue指令,辅助渲染当前的DOM结构【因为本质上里面的DOM结点都会出现在el区域称为html页面的结点】

<template>
	<h1>这是一个APP的自定义组件</h1>
	<!-- 使用{{}}插值表达式 -->
	<p>生成一个随机数: {{(Math.random()*10).toFixed(3)}}</p>
	<!-- 使用v-bind属性绑定指令 -->
	<p :title="new Date().toLocaleDateString()">和Cfeng一起学习vue3</p>
	<!-- 使用v-on实现事件绑定 -->
	<button @click= "console.log('Hello')">事件绑定</button>
</template>

在vue2.x版本中,< template> 结点内的DOM结点只是支持单个根结点,也即是,template中最外层【最高层】只能由一个根节点,多个就会报错

<template>
	<div> <!-- 最外层的根节点,vue2中支持一个根节点 -->
        <h1>.......</h1>
        <h2> </h2>
    </div>
</template>

在vue3.x中,支持定义多个根结点

<template>
    <h1>.......</h1>
     <h2> </h2>
</template>

script结点

vue规定: 组件内的script结点是可选的,可以在script结点中封装组件的JavaScript业务逻辑

<script>
	//组件相关的data数据,methods方法,都需要定义到export default所导出的对象中【默认导出】
    export default{}
</script>

script默认导出的对象,可以有如下的属性【结点】

  • name :可以通过name为当前组件自定义一个名称【首字母大写】,使用vue-tools调试的时候,可以清晰的看到是某一个组件【方便调试】
  • data : vue组件渲染期间需要用到的数据,就定义到data中【vue的dom结点中可以通过vue指定使用data数据,和之前的是相同的】,和之前相同,还是闭包的形式 【 在组件中,不能直接指向数据,会报错,必须return一个对象】
data() {
    return {
      count: 0
    }
  • methods : 组件的事件处理函数,必须定义到methods结点
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  data() {
    return {
      count: 0,
	  str: 'Cfeng, hello'
    }
  },
  methods:{
	  addNum(){
		  this.count ++;
	  }
  }
}

//行间进行事件绑定的时候,其中可以是methods中的方法的名称,还可以是一个JavaScript表达式,比如count++; flag = !flag;必须要这种对数值进行变化操作,但是console,alert等语句不行
  • props: 属性【类似于java的变量】,放置的变量,props接收的属性值不可以直接修改, 要想修改就要通过data中定义变量接收props中的数据,然后修改,优先级props > data【下面👇会详细解释】

配置项props接收数据的3中方式:

  1. 只是接收 : props:[‘name’,‘age’,‘sex’]
  2. 接收并限制类型 : props: {name:Number}
  3. 限制类型,必要性指定默认值
props:{
	"name":{type:String,required:true},
    "age":{type:Number,default:18}
}

style结点

vue规定:组件的< style> 结点是可选的,可以在style结点中编写样式美化当前组件的UI结构 ,其实可以给style标签指定lang,lang = ‘css’,属性可选,表示使用的样式语言,默认支持普通的css,可选值还有less,scss

<style lang="css">
	h1 {
		color: aqua;
	}
</style>

使用less(增强的css)会更加方便,因为less支持嵌套,css不支持,并且还可以定义变量

style支持less语法

如果希望使用less语法编写组件的style样式,需要进行配置

  • 运行npm i less -D 安装依赖包,提供less语法的编译支持【-d是安装到dev结点之下】
  • 在< style>标签上添加lang = 'less’属性,就可以使用
<style lang="less">
	h1 {
		color: aqua;
		i{
			color: blue;
		}
	}
</style>
//css是不支持嵌套的,所以h1内部的都是aqua,但是不会报错,改为less之后就可以显示两种颜色

可以看看整个helloworld组件

<template>
  <h1>{{ msg }}<i> cfeng.com</i></h1>
  <button @click="addNum">count is: {{ count }}</button><br>
  姓名 :<input type="text" v-model="str"/>
  <button @click="str += 'x'">test</button>
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  data() {
    return {
      count: 0,
	  str: 'Cfeng, hello'
    }
  },
  methods:{
	  addNum(){
		  this.count ++;
	  }
  }
}
</script>

<style lang="less">
	h1 {
		color: aqua;
		i{
			color: blue;
		}
	}
</style>

组件的基本使用

组件的注册

组件之间可以相互的引用: 比如App.vue根组件就引用了HelloWorld.vue这个自定义的子组件,引用之后根组件就可以使用子组件

组件注册有两种方式,分别是全局注册和局部注册

  • 全局注册: 可以在全局任何一个组件内使用,比如将轮播图组件swapper.vue注册为全局,那么A.vue和B.vue都可以使用
  • 局部组件:局部注册组件,只能在当前的注册范围中使用,比如在A.vue中注册,就只能在A.vue中使用
全局注册:

首先需要在main.js中导入需要注册的组件, 之后使用spa_app实例的component()方法,在全局注册组件,该方法第一个参数为注册成的名称,第二个参数为组件 其中,第一个参数时可省略的,和局部相同,如果省略,应用的时候就是直接时默认导入时的名称,而不是后面的重命名

//1.默认导入需要全局注册的组件HelloWorld.vue
import HelloWorld from './components/HelloWorld.vue'

//2.调用spa_app的实例components()方法,全局注册
spa_app.component("my-hello",HelloWorld)

spa_app.mount("#app")

全局注册组件时,要先注册之后,在mount挂载,不然会报错,Failed to resolve component

注册之后,就可以在任何位置,使用标签的形式来应用组件,标签名就是上面注册的名称;下面就是在根组件APP中应用Hello

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
 <!-- <HelloWorld msg="Hello Vue 3.0 + Vite" /> -->
  <my-hello msg = "Hello Vue 3.0+ Vi" />  //这里最好时独目的,双目的不报错
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'App',
  // components: {
  //   HelloWorld
  // }
}
</script>
局部注册

上面的注释就是局部注册,就是在需要使用的组件的内部,首先在script中导入待使用的组件; 之后就是默认导出的对象中与data平级的结点components中,注册组件, 注册的时候也可以自定义名称,也可以直接使用原来的名称

import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'App',
  components: {
    'my-hello':HelloWorld  //直接注册,就HelloWorld即可
  }
}

然后再template模板中直接使用标签引用即可

<my-hello msg="Hello Vue 3.0 + Vite" />

全局注册的组件:再任何一个组件中都可以使用全局注册组件;但是局部注册的组件,只能在注册的那个组件中使用

应用场景
如果某些组件在开发期间使用频率高,推荐全局注册,比如swaper

只是在特定情况下使用,推荐局部注册

组件注册的名称

之前说过,组件注册的时候,可以不重命名,直接使用默认导出的名称;也可以重命名成其他的名称,定义组件注册名称的方式有两种

  • 使用kebab-case命名法【短横线命名】 比如my-swaper,my-hello ; 使用的时候必须严格按照短横线名称来进行使用
  • 使用PasclCase命名法【大驼峰命名法(不是小驼峰)】,例如MyHello, 可以严格按照帕斯卡名称使用,也可以转化为短横线命名名称来使用
<template>
  <img alt="Vue logo" src="./assets/logo.png" />
 <my-hello msg="Hello Vue 3.0 + Vite" />
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'App',
  components: {
    'MyHello':HelloWorld
  }
}
    	//这里就不会报错

所以在开发中,最好使用帕斯卡命名法【大驼峰命名法】来对组件进行重命名,适用性更好

通过name属性注册名称

在注册组件期间,处理可以直接提供组件的注册名称之外,还可以把组件的name属性作为注册后组件的名称 【就是上面所演示的】,但是不是和默认导入相同,而是和name属性相同,只是恰好两者相同】

使用name属性注册,相当于使用的帕斯卡命名法

//全局注册
spa_app.component(HelloWord.name,HelloWord)


//局部注册
  components: {
    HelloWorld
  }

组件样式冲突

这里的例子就是App.vue嵌套了HelloWorld.vue,将父组件App.vue渲染到el区域

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <h1>APP.vue的文本内容</h1>
 <my-hello msg="Hello Vue 3.0 + Vite" />
</template>

这样根组件和子组件都有标签h1,现在想要将App组件的h1变为aqua颜色,那么加上样式

<style lang="less">
	h1 {
		color: aqua;
	}
</style>

出现了问题: 子组件HelloWord中的h1也变为了aqua,这就产生了样式冲突【没有独立】; 然后交换,父组件不声明样式,子组件使用之前的less样式,发现还是都变化了【…父子相互影响】

组件样式冲突原因

默认情况下,.vue组件中的样式全局生效,因此容易造成组件间的样式冲突 ----- 单页面程序SPA中,所有组件的DOM结构,都是基于唯一的index.html进行运行后呈现,每一个组件的样式,都会影响整个index.html页面的DOM元素

组件样式冲突的解决

为每一个组件分配唯一的自定义属性,在编写组件样式的时候,通过属性选择值来控制样式的作用域; 其实就是原生js中的选择器

比如将子组件HelloWorld的所有的结点按照vue2的格式放在一个根结点div中,为这个div添加属性选择值,定义样式时加上选择器

<template>
  <h1 data-v-001>{{ msg }}<i> cfeng.com</i></h1>
  <button data-v-001 @click="addNum">count is: {{ count }}</button><br>
  姓名 :<input data-v-001 type="text" v-model="str"/>
  <button data-v-001 @click="str += 'x'">test</button>
</template>

这里就给每一个结点加上了属性选择值data-v-001

然后下面编写样式的时候,就可以加上这个属性选择值,和之前的选择器类似,但是还是标签调用,而不是. #等, 加上域[]即可

<style lang="less">
	h1[data-v-001] {    //这里加上了作用域,就不会影响其他地方的h1标签
		color: aqua;
		i{
			color: blue;
		}
	}
</style>
style结点的scoped属性

手动像上面一样维护属性选择值很麻烦,并且发现同一个组件使用的都是唯一一个属性选择之并且都相同,所以就加上scoped属性,加上之后,系统自动为该组件所有的结点添加一个唯一的属性选择值,并且声明样式的时候只会作用与当前组件

<template>
  <h1>{{ msg }}<i> cfeng.com</i></h1>
  <button @click="addNum">count is: {{ count }}</button><br>
  姓名 :<input type="text" v-model="str"/>
  <button @click="str += 'x'">test</button>
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  data() {
    return {
      count: 0,
	  str: 'Cfeng, hello'
    }
  },
  methods:{
	  addNum(){
		  this.count ++;
	  }
  }
}
</script>

<style lang="less" scoped>
	h1 {
		color: aqua;
		i{
			color: blue;
		}
	}
</style>

所以一般情况下,组件之间都是独立的,所以所有的组件都要加上scoped属性

这样就会自动创建一个唯一的scope属性选择值 比如 < h1 data-v-62a9ebed="">Hello Vue 3.0 + Vite cfeng.com< /h1> 组件之间的值不一样,和之前手动写法时类似的;

/deep/样式穿透【vue3为:deep(选择器)】

如果给当前组件的style结点加上了scoped属性,那么当前组件的样式对子组件是不生效的,因为是不同的属性选择值;如果想要生效【比如两者就是样式相同】,那么就可以使用/deep/深度选择器

[@vue/compiler-sfc] the >>> and /deep/ combinators have been deprecated. Use :deep() instead.

这样子组件就会向上寻找到父组件中是否有该样式

<style lang="less" scoped>
// /deep/	h1 {
// 		color: aqua;
// 		i{
// 			color: blue;
// 		}
// 	}

:deep(h1) {
		color: aqua;
	}
</style>

组件的props

为了提高组件的复用性,在封装vue组件时要遵守的原则:

  • 组件的DOM结构,Style呀要尽量复用
  • 组件要展示的数据,尽量由组件使用者提供 之前的App使用HelloWord就传入了msg

为了方便使用者提供数据,vue使用了props

props时组件的自定义属性,组件的使用者可以通过props把数据传送到子组件的内部 供子组件内部进行使用

<my-hello msg = "你好,我是Cfeng"/>  //这里就将数据传递给了子组件HelloWord的msg这个props中

props作用: 父组件【使用者】通过props向子组件传递要展示的数据; 这样就可以提高复用性

组件中声明props

在vue组件中,可以将动态的数据声明为props自定义属性【data时常量,其中return的其实都是静态的数据,只是在dev-tools中调试可以修改,实际上没有变化,props类似于java中的变量】,自定义属性可以在当前组件的模板结构中直接被使用template中

<template>
  <h1>{{ msg }}<i> cfeng.com</i></h1>
  <button @click="addNum">count is: {{ count }}</button><br>
  姓名 :<input type="text" v-model="str"/>
  <button @click="str += 'x'">test</button>
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  }
}
    
接收的3中形式,没有定义类型var,就是一个数组,定义了类型,和默认值就是json格式
1. 只是接收 : props:['name','age','sex']
2. 接收并限制类型 : props: {'name':Number}
3. 限制类型,必要性指定默认值

这里就声明了一个String类型的变量msg,然后App调用的时候传入数据

无法使用未声明的props

如果父组件给子组件传递了未声明的props属性,则这些属性会被忽略,无法被子组件使用

就是要使用的值必须要在props中进行声明,没有声明,data静态量中也没有,就渲染不出结果

动态绑定props的值

props和data的常量是相同用法,比如上面演示的插值表达式,v-bind属性绑定,还有就是v-modle双向数据绑定都是可以的

这里的动态绑定: 就是说props定义的属性也是组件标签的属性,那么就可以像普通标签进行动态的属性绑定,比如在APP.vue中,动态绑定msg 【 这样就可以一环套一环,不用一开始就赋值】

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <h1>APP.vue的文本内容</h1>
 <my-hello :msg = 'str'></my-hello>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'App',
  data(){
	  return {
		  str:'Hello Vue 3.0 + Vite1'
	  }
  },
  components: {
    'MyHello':HelloWorld
  }
}
</script>

这样就在data中动态将数据绑定给属性props

props的大小和命名

组件中如果使用cameCase小驼峰命名法声明props属性的名称,【这和之前的大驼峰命名组件相同】,那么就可以使用两种方式绑定值

直接使用驼峰原名,比如myMsg, 还可以使用短横线的方式,比如my-msg【但是只是在传递属性的时候才可以修改,在内部使用,比如插值表达式中必须相同】

Class与Style绑定

在实际开发中经常遇到动态操作元素样式的需求,因此vue允许通过v-bind属性绑定指令,为元素动态绑定class属性值和行内的style样式

动态绑定HTML中的class

可以通过三元表达式,动态为元素绑定class的类名

//比如这里isItalic为boolean类型,判断是否倾斜
 <h1 class= 'beblue' :class = "isItalic ? 'italic' : ''">{{ msg }}<i> cfeng.com</i></h1>
 <button @click="isItalic = !isItalic">test</button>

  data() {
    return {
      count: 0,
	  str: 'Cfeng, hello',
	  isItalic: true
    }
  },

----下面就是两种不同的样式----
<style lang="less" scoped>
	.beblue {
		color: aqua;
		i{
			color: blue;
		}
	}

	.italic {
		font-style: italic;
	}
</style>

这样简单点击按钮就可以修改样式: 注意:这里的italic一定要加上"",不然就会被认为是一个property,找不到就报错

通过数组语法绑定Html的class

如果元素需要动态绑定多个class的类名,可以通过数组的方式实现

因为一个三元组可以动态添加或者移除一个样式,所以数组中就存放多个三元组就可以实现多个样式的绑定了

//这里在上面的基础上新增一个class
 <h1 class= 'beblue' :class = "[isItalic ? 'italic' : '',isDelete ? 'delete' : '']">{{ msg }}<i> cfeng.com</i></h1>
<button @click="isItalic = !isItalic">倾斜</button>
<button @click="isDelete = !isDelete">删除线</button>

data() {
    return {
      count: 0,
	  str: 'Cfeng, hello',
	  isItalic: false,
	  isDelete: false
    }
  },

<style lang="less" scoped>
	.beblue {
		color: aqua;
		i{
			color: blue;
		}
	}

	.italic {
		font-style: italic;
	}
	
	.delete {
		text-decoration: line-through;
	}
</style>

这样点击按钮就可以实现样式的切换

以对象的方式绑定

以数组的方式绑定的缺点就是非常的冗余,模板结构臃肿,此时可以使用对象的语法进行简化\

在data中定义一个对象classObj,其中属性名为class,值为boolean类型

  <h1 class= 'beblue' :class = "classObj">{{ msg }}<i> cfeng.com</i></h1>
<button @click="classObj.italic = !classObj.italic">倾斜</button>
  <button @click="classObj.delete = !classObj.delete">删除线</button>

  data() {
    return {
      count: 0,
	  str: 'Cfeng, hello',
	  classObj:{
		  italic: false,
		  delete: false
	  }
    }

<style lang="less" scoped>
	.beblue {
		color: aqua;
		i{
			color: blue;
		}
	}

	.italic {
		font-style: italic;
	}
	
	.delete {
		text-decoration: line-through;
	}
</style>

需要注意的是,classObj对象中,键值对的键就直接是定义的类名,值为boolean

以对象语法绑定内联的style

:style 的对象语法十分直观 ----- 这是一个JavaScript对象。CSS property名可以用驼峰或者短横线命名

<h1 :style = "{color: XX, font-size: XX, background-color: XX}"></h1>

这样就可以将数据源中的数据动态绑定到标签上

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <h1 :style="{'background-color':backColor,'font-size': fontSize,'font-style': fontStyle}">APP.vue的文本内容</h1>
 <my-hello :msg = 'str'></my-hello>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'App',
  data(){
	  return {
		  str:'Hello Vue 3.0 + Vite1',
		  backColor: 'red',
		  fontSize: 20,
		  fontStyle: 'italic'
	  }
  },
  components: {
    'MyHello':HelloWorld
  }
}
</script>

这里的样式名要么直接写驼峰的方式,如果要用原来的名称,必须用单引号包裹;在dev-tool中直接会转换成小驼峰的方式

封装组件案例

这里的案例就是要封装一个MyHeader组件,需求:

  1. 允许用户自定义title标题
  2. 允许用户自定义bgcolor颜色
  3. 允许用户自定义color文本颜色
  4. MyHeader组件需要在页面顶部进行fixed固定,z-index为990【防止被覆盖】
<template>
	<div class="header-container" :style="{backgroundColor:bgcolor,color:color}"> <!-- 这里简单放一个根结点 -->
		{{title || 'Header 组件'}}
	</div>
</template>

<script>
	export default {
		name: 'MyHeader',
		props: ['title','bgcolor','color']
	}
</script>

<style lang="less" scoped>
	.header-container {
		height: 45px;   //一般标题就是45px高度
		background-color: pink;
		text-align: center;
		line-height: 45px;
		position: fixed; //就不会浮动
		top: 0; //上间距和左间距
		left: 0;
		width: 100%;
		z-index: 999;
	}
</style>

然后在App.vue中使用这个组件即可;

<my-header :title = "mytitle" :bgcolor = "mybgcolor" :color = "mycolor"/>

传入属性即可看到完整的效果🌳

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值