深入理解CSS继承与LocalStorage:从基础到实战应用

43 阅读6分钟

深入理解CSS继承与LocalStorage:从基础到实战应用

前端开发中,CSS的继承特性和LocalStorage的本地存储功能是两个非常重要且实用的概念。本文将结合具体代码示例,深入探讨这两个主题,并展示如何在实际项目中巧妙运用它们。

一、CSS继承属性详解

1.1 什么是CSS继承?

CSS继承是指某些CSS属性能够从父元素传递到子元素的特性。这一机制让我们的样式编写更加高效,避免了重复代码。 会继承的CSS属性

  • 字体相关:font-family, font-size, font-weight
  • 文本相关:color, text-align, line-height
  • 列表相关:list-style-type
  • 可见性:visibility

不会继承的CSS属性

  • 盒模型相关:width, height, margin, padding
  • 背景相关:background-color, background-image
  • 定位相关:position, top, left
  • 布局相关:display, float, overflow

1.2 继承实战分析

让我们通过一个具体例子来理解CSS继承:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>css继承属性</title>
    <style>
        body{
            background-color: green; /* body背景色设置为绿色 */
        }
    </style>
</head>
<body>
    <p>Hello World</p>
    <!-- overflow 属性不会被子元素继承 -->
    <div style="overflow: hidden; font-size: 28px; height:300px; background-color:yellow; color:pink">
        你好
        <!-- height: inherit 明确指示子元素继承父元素的高度 -->
        <p style="background-color: red;height: inherit;">三国演义</p>
    </div>
    <div>1111</div>
</body>
</html>

在这个例子中:

  • font-sizecolor会继承到子元素<p>
  • background-color不会继承,所以子元素设置了红色背景
  • overflow: hidden不会继承,子元素不受影响
  • height: inherit明确指示子元素继承父元素的高度

1.3 控制继承的CSS值

CSS提供了几个特殊值来控制继承行为:

  • inherit:明确继承父元素的值
  • initial:使用属性的初始值
  • unset:如果是继承属性则继承,否则使用初始值

二、CSS Reset与全局样式设置

在现代前端开发中,合理的CSS重置和全局设置至关重要:

html{
    box-sizing: border-box; /* 设置盒模型为border-box */
    min-height: 100vh; /* 最小高度为视口高度 */
    display: flex; /* 弹性格式化上下文 */
    justify-content: center; /* 水平居中 */
    align-items: center; /* 垂直居中 */
    text-align: center; /* 文本居中 */
}
/* 通配符选择器,应用于所有元素及伪元素 */
*,*::before,*::after{
    box-sizing: inherit; /* 继承盒模型设置 */
}
.wrapper{
    padding: 20px;
    max-width: 350px;
    background-color: rgba(255, 255, 255, 0.95); /* 半透明白色背景 */
    box-shadow: 0 0 0 10px rgba(0, 0, 0, 0.1); /* 盒子阴影:水平偏移 垂直偏移 模糊半径 扩散半径 */
}
h2{
    text-align: center;
    margin: 0;
    font-weight: 200; /* 细体字 */
}
.plates{
    margin: 0;
    padding: 0;
    text-align: left;
    list-style: none; /* 移除列表默认样式 */
}
.plates li{
    border-bottom: 1px solid rgba(0, 0, 0, 0.2); /* 底部边框 */
    padding: 10px 0;
    font-weight: 100;
    display: flex; /* 设置弹性格式化上下文 */
}
.plates label{
    flex: 1; /* 弹性布局,占满剩余空间 */
    /* cursor属性用于设置鼠标指针在元素上时显示的光标样式 pointer表示可以点击的手型👆👆 */
    cursor: pointer;
}
.plates input{
    display: none; /* 隐藏原生checkbox */
}
/* 使用伪元素自定义checkbox样式 */
.plates input + label:before{
     content: "⬜⬜️"; /* 未选中状态 */
     margin-right: 10px;
}
.plates input:checked + label:before{
    content: "✅"; /* 选中状态 */
}
.add-items{
    margin-top: 20px;
}
.add-items input{
    padding: 10px;
    outline: 5px solid rgba(14, 14, 211, 0.8); /* 轮廓线,不占据布局空间 */
    border: 1px solid rgba(0, 0, 0, 0.1);
}

这段代码做了以下几件事:

  1. 盒模型统一:通过box-sizing: border-box让所有元素的宽度计算包含padding和border
  2. 继承盒模型:使用box-sizing: inherit确保所有元素和伪元素都继承这一设置
  3. Flexbox居中:通过Flexbox实现完美的垂直水平居中
  4. 自定义表单控件:通过CSS伪元素自定义checkbox样式

三、LocalStorage深度解析

3.1 LocalStorage基础

LocalStorage是HTML5提供的Web Storage API的一部分,用于在浏览器中持久存储数据。 主要特性

  • 存储容量:通常为5MB左右
  • 生命周期:数据永久存储,除非手动清除
  • 作用域:同一域名下的所有页面共享
  • 数据类型:仅支持字符串存储

3.2 LocalStorage核心API

// 存储数据
localStorage.setItem('key', 'value');

// 读取数据
const data = localStorage.getItem('key');

// 删除特定数据
localStorage.removeItem('key');

// 清空所有数据
localStorage.clear();

// 获取键名
const keyName = localStorage.key(index);

3.3 实战:TodoList应用

下面是一个完整的TodoList应用,结合了CSS继承和LocalStorage:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>LocalStorage Todos</title>
    <link rel="stylesheet" href="./common.css">
</head>
<body>
    <div class="wrapper">
        <h2>LOCAL TAPAS</h2>
        <p></p>
        <ul class="plates">
            <li>Loading tapas....</li>
        </ul>
        <form class="add-items">
            <input 
            type="text" 
            placeholder="Item Name"
            required
            name="item"
            >
            <input type="submit" value="+ Add Item">
        </form>
    </div>
    <script>
        // 获取DOM元素
        const addItems = document.querySelector('.add-items');
        const itemList = document.querySelector('.plates');
        // 从localStorage读取数据,如果没有则初始化为空数组
        const items = JSON.parse(localStorage.getItem('todos'))||[];
        
        // 函数式封装,拒绝流程式代码
        // 封装实现的细节,比较难,封装的人和调用的人是两波人
        // 复用
        // 函数默认值是es6
        // 流程式代码超过10行,一定要封装函数
        function populateList(plates=[],platesList){
            platesList.innerHTML= plates.map((plate,i)=>{
                return `
                    <li>
                        <input type="checkbox" data-index=${i} id="item${i}" 
                            ${plate.done?'checked':''} <!-- 根据完成状态设置checked属性 -->
                        />   
                        <label for="item${i}">${plate.text}</label>
                    </li>
                `
            }).join('') // 将数组转换为字符串
        }
        
        function addItem(event){
            event.preventDefault(); // 阻止默认行为(表单提交刷新页面)
            console.log('/////////')
            // 函数执行的时候会有this 事件处理函数的时候,指向form
            const text = (this.querySelector('[name=item]').value.trim()) // 获取表单的值,.trim()用于移除字符串两端的空白值
            const item = {
                text,
                done:false
            }
            items.push(item);
            // 持久化存储key=>value
            localStorage.setItem('todos',JSON.stringify(items))
            populateList(items,itemList);
            this.reset() // 清空表单内容
        }
        
        function toggleDone(event){
            const el=event.target
            console.log(el.tagName,'?/?/')
            // 使用事件委托,只处理checkbox的点击
            if(el.tagName == 'INPUT'){
                const index= el.dataset.index;
                items[index].done = !items[index].done
                localStorage.setItem('todos',JSON.stringify(items));
                populateList(items,itemList);
            }
        }
        
        // 事件监听
        addItems.addEventListener('submit',addItem);
        itemList.addEventListener('click',toggleDone) // 事件委托模式,给父元素ul绑定来监听所有子元素
        
        // 初始渲染
        populateList(items,itemList);
    </script>
</body>
</html>

四、代码优化与最佳实践

4.1 函数封装的重要性

从上面的代码中我们可以看到良好的函数封装习惯:

// 不好的写法:流程式代码
// 直接写操作逻辑,难以复用和维护

// 好的写法:函数式封装
function populateList(plates = [], platesList) {
    // 封装渲染逻辑
}

function addItem(event) {
    // 封装添加逻辑
}

function toggleDone(event) {
    // 封装状态切换逻辑
}

封装的好处

  • 复用性:可以在多个地方调用同一个函数
  • 可维护性:修改逻辑只需在一个地方进行
  • 可读性:函数名清晰表达意图,代码更易理解
  • 团队协作:不同开发者可以并行工作

4.2 事件委托的巧妙运用

// 传统方式:为每个元素单独绑定事件
// 当列表项很多时性能较差

// 事件委托方式:只在父元素上绑定一个事件监听器
itemList.addEventListener('click', toggleDone);

事件委托的优势

  • 性能优化:减少事件监听器数量
  • 动态元素支持:对新添加的元素自动生效
  • 内存效率:避免内存泄漏

4.3 CSS继承的实际应用

在项目中合理运用CSS继承:

/* 在父元素设置,子元素继承 */
.plates li {
    font-weight: 100; /* 子元素会继承此字体粗细 */
    color: #333; /* 子元素会继承此颜色 */
}

/* 明确继承 */
.plates input:checked + label {
    color: inherit; /* 明确继承父元素颜色 */
}

五、总结

通过这个完整的TodoList项目,我们深入理解了:

  1. CSS继承机制:如何合理利用继承减少代码重复
  2. LocalStorage应用:实现数据的持久化存储
  3. 现代JavaScript编程:函数式封装、事件委托等最佳实践

这个项目展示了前端开发中多个重要概念的有机结合,是学习现代Web开发的优秀范例。掌握这些技术后,你可以轻松构建出功能完善、用户体验良好的Web应用。 关键要点回顾

  • CSS继承让样式更简洁易维护
  • LocalStorage提供客户端持久化存储能力
  • 函数封装提高代码质量和可维护性
  • 事件委托优化性能和动态内容处理