一、scoped样式属性(局部范围样式)及lang=" "的运用(默认情况下自动选择css,也不会出现lang=""让你选择语言的提示)
scoped样式属性
如果我们给两个子组件中添加的样式类名相同就会出现类名冲突的问题,
vue显然页面的时候会最终把最后在app.vue中组测的组件的类名中的样式,
渲染出来!
例如:
LqjSchool.vue:
<template><divclass="School"><h2>学校名称:{{name}}</h2><h2>学校地址:{{address}}</h2></div></template> ... <style>.School{ background: rgb(23, 190, 241); } </style>
StudentLqj.vue:
<template><divclass="School"><h2>学生姓名:{{name}}</h2><h2>学生性别:{{msg}}</h2></div></template> ... <style>.School{ background: rgb(248, 120, 0); } </style>
App.vue:
importLqjSchoolfrom'./components/LqjSchool.vue'importStudentLqjfrom'./components/StudentLqj.vue'
注意:LqjSchool.vue中School的背景色为天蓝色
StudentLqj.vue中School的背景色为橙色
结果:页面中渲染出的文字的背景颜色是StudentLqj.vue中.School的颜色:橙色
如果我们项避免出现这种情况解决方法:
1.在不同的子组件中写不同的样式名
2.给每一个子组件中的<style>添加scoped属性
例如:<style scoped> </style>
这样我们写的样式名即使多个组件都一样,也不会出现冲突!
scoped样式属性(局部范围样式)
原理:
原理:当我们用scoped属性来限制样式标签时,在页面渲染时会给用样式的每个<div>中的标签一个随机的id,根据此id来对应限制的标签,从而达到限制局部效果!
lang=" "的运用
此属性是供开发者在<style>标签中选择样式语言的(以css和less为例)
1.如果开发者想用css来写样式属性:
<stylelang="css"scoped>.School{ background: rgb(23, 190, 241); } </style>
2.如果开发者想用less来写样式属性:
<stylelang="less"scoped>.School{ background: rgb(23, 190, 241); } </style>
注意:默认情况下less是vue编译不了的我们必须借助
(终端命令:npm i less-loader)才能正常运行。但也有可能报错:
原因你的vue脚手架调用的webpack的版本兼容问题!
查看webpack版本终端命令中输入:
npm view webpack versions
查看less-loader版本终端命令中输入:
npm view less-loader versions
安装:(我们以7版本为例)
npm i less-loader@7
二、nanoid(类型函数)直接去调用它,就能给出一个唯一的字符串
首先需要安装:
npm i nanoid
它使用分别暴露的形式,所以这样引入:
import {nanoid} from 'nanoid'
举例:
<script>import {nanoid} from'nanoid'exportdefault{ name:'Myheader', methods:{ add(e){//e事件对象//将用户的输入包装成为一个todos对象constObj= {id:nanoid()} } } } </script>
结果显示:
这个库会随机生成一个id
三、小案例(基础版):
app.vue:
<template><divid="root"><divclass="box"><spanclass="haizei">oen piece,记录本</span></div><divclass="todo-container"><divclass="todo-wrap"><Myheader:addTodos="addTodos"></Myheader><List:todos="todos":checkTodo="checkTodo":deleteTodo="deleteTodo"></List><Myfooter:todos="todos":checkAllTodo="checkAllTodo":clearAllTodo="clearAllTodo"></Myfooter></div></div></div></template><script>// 引入School组件 importMyheaderfrom'./components/Myheader.vue'importListfrom'./components/List.vue'// 因为List是Item的父组件,所以不用引入Item// import Item from './components/Item.vue'importMyfooterfrom'./components/Myfooter.vue'exportdefault { name: 'App', // msg里面要接受到的数据开始components: {Myheader,List, // Item,Myfooter,}, data(){ return{ todos:JSON.parse(localStorage.getItem('todos')) || [] // todos:[// // {id:'001',title:'学vue+写csdn',done:true},// // {id:'002',title:'吃饭',done:false},// // {id:'003',title:'学高数+四级',done:false}// ] } }, methods:{ //添加一个todoObjaddTodos(Obj){ this.todos.unshift(Obj) }, //勾选或取消勾选todoObjcheckTodo(id){ this.todos.forEach((todoObj)=>{ //函数体if(todoObj.id===id) todoObj.done=!todoObj.done }) }, //删除一个todoObjdeleteTodo(id){ this.todos=this.todos.filter((todoObj)=>{ returntodoObj.id!==id }) }, //全选or全不选checkAllTodo(done){ this.todos.forEach((todoObj)=>{ todoObj.done=done }) }, //清除所有已经完成的todosclearAllTodo(){ this.todos=this.todos.filter((todoObj)=>{ return!todoObj.done }) } }, watch:{ todos:{ deep:true, handler(value){ localStorage.setItem('todos',JSON.stringify(value)) } } } } </script><style>/*base*/body { background-image: url(../src/assets/1.png) ; Opacity:1} .btn { display: inline-block; padding: 4px12px; margin-bottom: 0; font-size: 14px; line-height: 20px; text-align: center; vertical-align: middle; cursor: pointer; box-shadow: inset01px0rgba(0, 255, 64, 0.2), 01px2pxrgba(11, 88, 255, 0.05); border-radius: 4px; } .btn-danger { color: #fff; background-color: #1cda45; border: 1pxsolid#0d8fe6; } .btn-danger:hover { color: #fff; background-color: #f70ea9; } .btn:focus { outline: none; } .todo-container { width: 600px; margin: 0auto; } .todo-container.todo-wrap { padding: 10px; border: 1pxsolidrgb(250, 150, 0); border-radius: 5px; } .box{ display: flex; flex-direction: row; justify-content: space-around; } .haizei{ font-size: 50px; color: rgb(245, 147, 0); font-weight: 800; } </style>
Item.vue:
<template><li><label><inputtype="checkbox":checked="todoObj.done"@change="handleCheck(todoObj.id)"/><!-- <input type="checkbox" v-model="todo.done"></input> --><spanclass="ziti">{{todoObj.title}}</span><!-- <span>{{todoObj.done}}</span> --></label><buttonclass="btn btn-danger"@click="handleDelete(todoObj.id)">删除</button></li></template><script>exportdefault{ name:'Item', //生命接受todoObj对象props:['todoObj','checkTodo','deleteTodo'], methods:{ //勾选or取消勾选handleCheck(id){ //通知App组件将对应的todo对象done值取反this.checkTodo(id) }, //删除handleDelete(id){ //通知App组件将对应的todo对象done值取反if(confirm('确定删除吗?')){ this.deleteTodo(id) } }, } } </script><stylescoped>/*item*/li { list-style: none; height: 36px; line-height: 36px; padding: 05px; border-bottom: 1pxsolid#ddd; } lilabel { float: left; cursor: pointer; } lilabelliinput { vertical-align: middle; margin-right: 6px; position: relative; top: -1px; } libutton { float: right; display: none; margin-top: 3px; } li:before { content: initial; } li:last-child { border-bottom: none; } li:hover{ background: rgb(129, 3, 247); } li:hoverbutton{ display: block; } .ziti{ font-size: 15px; color: aliceblue; } </style>
Myfooter.vue:
<template><divclass="todo-footer"v-show="total"><label><inputtype="checkbox":checked="isAll"@change="checkAll"/></label><spanclass="wenzi"><span>已完成{{doneTotal}}</span> / 全部{{total}} </span><buttonclass="btn btn-danger"@click="clearAll">清除已完成任务</button></div></template><script>exportdefault{ name:'Myfooter', props:['todos','checkAllTodo','clearAllTodo'], computed:{ total(){ returnthis.todos.length }, doneTotal(){ // let i = 0// this.todos.forEach((todoObj)=>{// if(todoObj.done) i++// })// return i returnthis.todos.reduce((pre,todoObj)=>pre+ (todoObj.done?1 : 0),0) }, isAll(){ returnthis.doneTotal===this.total&&this.total>0 } }, methods:{ checkAll(e){ this.checkAllTodo(e.target.checked) }, clearAll(){ this.clearAllTodo() } } } </script><stylescoped>/*footer*/.todo-footer { height: 40px; line-height: 40px; padding-left: 6px; margin-top: 5px; } .todo-footerlabel { display: inline-block; margin-right: 20px; cursor: pointer; } .todo-footerlabelinput { position: relative; top: -1px; vertical-align: middle; margin-right: 5px; } .todo-footerbutton { float: right; margin-top: 5px; } .wenzi{ font-size: 20px; color: azure; } </style>
Myheader.vue:
<template><divclass="todo-header"><inputtype="text"placeholder="请输入你的任务名称,按回车键确认"v-model="title"@keyup.enter="add"/></div></template><script>import {nanoid} from'nanoid'exportdefault{ name:'Myheader', props:['addTodos'], data(){ return{ title:'' } }, methods:{ add(){ //校验数据if(!this.title.trim()) returnalert('输入不能为空') //将用户的输入包装成为一个todos对象constObj= {id:nanoid(),title:this.title,done:false} //通知app组件去添加一个todos对象this.addTodos(Obj) //清空输入框的内容this.title=" " } } } </script><stylescoped>/*header*/.todo-headerinput { width: 560px; height: 28px; font-size: 14px; border: 1pxsolid#ccc; border-radius: 4px; padding: 4px7px; } .todo-headerinput:focus { outline: none; border-color: rgba(82, 168, 236, 0.8); box-shadow: inset01px1pxrgba(0, 0, 0, 0.075), 008pxrgba(82, 168, 236, 0.6); } </style>