css3 transition 实例及分析 图片hover出现文字 sidebar平滑过渡(动画系列3)

本文深入探讨CSS3的transition属性,通过实例分析了transition在div和div:hover上的不同应用,解释了为何在某些情况下高度变化可能不会产生过渡效果,并展示了图片颜色转换和平滑sidebar过渡等应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

<span style="background-color: rgb(255, 0, 0);"><span style="font-size:24px;">一、</span></span>
<!DOCTYPE html> 
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>CSS3 transition-property属性</title>
    <style type="text/css">
        div
        {
            display:inline-block;
            width:100px;
            height:50px;
            background-color:#14C7F3;
            
        }
        div:hover
        {
            height:100px;
            transition-property:height;
            transition-duration:0.5s ;
            transition-timing-function:linear;
            transition-delay:0;
        }
    </style>
</head>
<body>
    <div></div>
</body></html>

<!DOCTYPE html> 
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>CSS3 transition-property属性</title>
    <style type="text/css">
        div
        {
            display:inline-block;
            width:100px;
            height:50px;
            background-color:#14C7F3;
	        transition-property:height;
            transition-duration:0.5s ;
            transition-timing-function:linear;
            transition-delay:0;          
        }
        div:hover
        {
            height:100px;
                    }
    </style>
</head>
<body>
    <div></div>
</body>
</html>


这两者的区别是一个transition写在了div里,一个写在了div:hover里,这两者的区别是,第1个是鼠标移上去,移开都有过渡效果;第2个只有鼠标移上去有过渡效果,鼠标移开时没有过渡,而是直接变化,所以一般transition是写在元素中,而不是元素的伪类里。二、

<!DOCTYPE html>
<html xmlns= "http://www.w3.org/1999/xhtml" >
<head>
     <title>CSS 3 实现鼠标移上去显示全部内容</title>
     <style type= "text/css" >
         #container
         {
             text- overflow :ellipsis;
             overflow : hidden ;
             white-space : nowrap ;
             border : 1px solid gray ;
             width : 300px ;
             padding : 20px ;
             color :raba( 0 , 0 , 0 , 0.7 );
             cursor : pointer ;
         }
         #container:hover
         {
             white-space : normal ;
             height : 148px ;
             background-color : #F2F9F9 ;
             transition-property:background-color,height;
             transition-duration: 0.2 s ;
             transition-timing-function:linear;
         }
     </style>
</head>
<body>
     <div id= "container" >这里事实上height元素的高并没有过渡,而是直接变化,应该是div里并没有设置高度,事实上在div里加了height后,height也平滑过渡了 。</div>
</body>
</html>

这里事实上height元素的高并没有过渡,而是直接变化,应该是div里并没有设置高度,事实上在div里加了height后,height也平滑过渡了

 

三、

<!DOCTYPE html>
<html xmlns= "http://www.w3.org/1999/xhtml" >
<head>
     <title>CSS 3 过渡</title>
     <style type= "text/css" >
         div
         {
             display :inline- block ;
             width : 100px ;
             height : 100px ;
             border-radius: 0 ;
             background-color : #14C7F3 ;
             transition-property:border-radius;
             transition-duration: 0.5 s;
             transition-timing-function:linear;
             transition-delay: 0 ;
         }
         div:hover
         {
             border-radius: 50px ;
         }
     </style>
</head>
<body>
     <div></div>
</body>
</html>

这个例子是把方形渐变成了圆形,当鼠标移动到div元素上面时,div元素圆角半径在0.5秒内从0过渡到50px

四、

<!DOCTYPE html>
<html xmlns= "http://www.w3.org/1999/xhtml" >
<head>
     <title>CSS 3 实现图片文字介绍滑动展示效果</title>
     <style type= "text/css" >
         #info
         {
             width : 760px ;
             margin : 0 auto ;
         }
         /*定义外层样式*/
         .wrap
         {
             width : 220px ;
             height : 330px ;
             float : left ;
             position:relative;
            overflow:hidden;
             font-family :arial, sans-serif;
         }
         .wrap img
         {
             border : 0 ;
             width : 220px ;
             height : 330px ;
         }
         .wrap p
         {
             display : block ;
            width:220px;
            height:330px;
position:absolute;
            left:0;
            top:300px;
            background-color:rgba(0,0,0,0.3);/*使用CSS3 RGBA颜色值*/
             font-size : 12px ;
             color : #FFFFFF ;
             padding : 0 ;
             margin : 0 ;
             line-height : 16px ;
             transition: all 0.6 s ease-in-out; /*定义CSS3过渡效果,all表示过渡属性针对所有值有变化的CSS属性*/
         }
         .wrap p b
         {
             display : block ;
             font-size : 22px ;
             color : #fc0 ;
             text-align : center ;
             margin : 0 ;
             padding : 0 ;
             line-height : 30px ;
          }
         .wrap p span
         {
             display : block ;
             padding : 10px ;
             line-height : 20px ;
         }
         .wrap:hoverp { top : 0 ;}
     </style>
</head>
<body>
     <div id= "info" >
         <div class= "wrap" >
             <img src= "#" alt= "" >
             <p>
                 <b>Red Eye Frog</b>
                 <span> 昨夜一梦,你经过这里,情境忽明忽暗,我从你的怀抱里挣脱,没有抽出一点点丝来。我向桑叶靠拢,把一片春光拢在怀里,滚圆的身躯,坐卧在春天的一个角落,待阳光慢慢靠近,在一段柔波里,细细地浣纱。梦里,我唤你亲,一层一层地剥开,一片一片地浸润,感知你内心的独白 </span>
             </p>
         </div>
         <div class= "wrap" >
             <img src= "#" alt= "" >
             <p>
                 <b>Emperor Penguin</b>
                 <span> 你未曾给过我抵达你心底的机会,即使我再奋不顾身的追逐,也无法跃进你的世界。不是蝴蝶飞不过沧海,而是沧海的那端,从未有过等待。我在凌氏基层实习初次遇见凌玺御,他当时身着浅蓝牛仔裤纯白T恤神色淡然的从我身边擦肩而过时,我那么清晰的感受到了 </span>
             </p>
         </div>
         <div class= "wrap" >
             <img src= "#" alt= "" >
             <p>
                 <b>Pelicans</b>
                 <span> 阳光斑驳了影子在天空中我用手指描绘你的名字海棠树下花落肩头数不清缠绵的记忆且不说忘川河畔千百世为你独开的彼岸亦不说奈何桥边日夜空守你不变的容颜恍惚、迷离~流年在我指尖绕成红线在云霞的彼端折一只千纸鹤放在风中放掉我的过去还有那绿荫下白衣少年 </span>
             </p>
         </div>
     </div>
</body>
</html>
这是图片文字介绍滑动效果,它的原理是<p>top为300px,<span>里的文字介绍就会看不到;然后

.wrap:hover p {top:0;},文字介绍就会出现了,这里成功的关键就是position,overflow用的好。过程用了过渡。

五、

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>CSS3实现图片文字介绍滑动展示效果</title>
    <style type="text/css">
        #info
        { 
            width:760px; 
            margin:0 auto;
        }
        /*定义外层样式*/
        .wrap 
        {
            width:220px; 
            height:330px; 
            float:left;
            position:relative; 
            overflow:hidden; 
            font-family:arial, sans-serif; 
        }
        .wrap img 
        {
            border:0;
            width:220px;
            height:330px; 
        }
        .wrap p 
        {
            display:block; 
            width:220px; 
            height:30px; 
            position:absolute; 
            left:0; 
            top:330px; 
            background-color:rgba(0,0,0,0.3);/*使用CSS3 RGBA颜色值*/
            font-size:12px; 
            color:#FFFFFF; 
            padding:0; 
            margin:0; 
            line-height:16px;
            transition: all 0.3s ease-in-out;/*定义CSS3过渡效果,all表示过渡属性针对所有值有变化的CSS属性*/
        }
        .wrap p b 
        {
            display:block; 
            font-size:22px; 
            color:#fc0; 
            text-align:center;
            margin:0; 
            padding:0; 
            line-height:30px;
         }
       
        .wrap:hover p {top:300px;}
    </style>
</head>
<body>
	<div id="info">
		<div class="wrap">
			<img src="#" alt="">
			<p>
				<b>Red Eye Frog</b>
	
			</p>
		</div>
		<div class="wrap">
			<img src="#" alt="">
			<p>
				<b>Emperor Penguin</b>
	
			</p>
		</div>
		<div class="wrap">
			<img src="#" alt="">
			<p>
				<b>Pelicans</b>
	
			</p>
		</div>
    </div>
</body>
</html>

模仿了第五个

六、

<!DOCTYPE html>
<html>
<meta charset="utf-8">  
<head>
<style> 
*{margin:0;padding:0;}
p
{	
	width:100px;
	height:100px;
	position:absolute;
	top:30px;
	background-color: rgba(255,255,255,0.5);
transform:translate(-100px);
-moz-transform:translate(-100px); /* Firefox 4 */
-webkit-transform:translate(-100px); /* Safari and Chrome */
-o-transform:translate(-100px); /* Opera */</span>
transition:all 2s;
-moz-transition:all 2s; /* Firefox 4 */
-webkit-transition:all 2s; /* Safari and Chrome */
-o-transition:all 2s; /* Opera */
}
img 
        {
            border:0;
            width:600px;
            height:300px; 
        }
div
{
width:100px;
height:100px;
background:red;

}
div:hover p
{

<span style="color:#ff0000;">transform:translate(0px);
-moz-transform:translate(0px); /* Firefox 4 */
-webkit-transform:translate(0px); /* Safari and Chrome */
-o-transform:translate(0px); /* Opera */</span>
}
</style>
</head>
<body>
<div><img src="bg_3.jpg"><p>请把鼠标指针放到黄色的 div 元素上,来查看过渡效果。</p></div>
</body>
</html>
这是transform的变化引起的好玩的效果,文字从无到有,从左边缘滑到图片上,很不错的效果。

七、图片的由灰色变成彩色

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
</head>
<style type="text/css">	
	 *{
            margin:0;
            padding:0;
            list-style: none;
        }
        body{}
        #container{
            width:1000px;height:400px;
            margin:20px auto;    
        }
       a img{
        	-webkit-filter:grayscale(80%);
        	
   
    -webkit-transition:-webkit-filter 1s ease-in-out;  
        }
        a:hover img{
        	-webkit-filter:grayscale(0);
        }
</style>
<body>
	<div id="container">
		<a href="#"><img src="bg_1.jpg"></a>
		<a href="#"><img src="bg_2.jpg"></a>
		<a href="#"><img src="bg_3.jpg"></a>
		<a href="#"><img src="bg_4.jpg"></a>
		<a href="#"><img src="bg_5.jpg"></a>
	</div>
</body>
</html>
用到了滤镜filter,改变其灰度值

八、sidebar

<span style="background-color: rgb(255, 255, 204);"><!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
</head>
<style>
	*{
	margin:0px;
	padding: 0px;
	font-family: '微软雅黑',Roboto
}

#header{
	position: absolute;
	display: block;
	width: 100%;
	height:10%;
	top:0px; 
	box-shadow: 0px 2px 4px #aaa;
	overflow: hidden;
}
#header #hamburger-icon,#more-icon{
	cursor: pointer;
	margin-top: 1.6%;
}
#header #hamburger-icon{
	float: left;
	margin-left: 30px;

}
#header #more-icon{
	float: right;
	margin-right: 30px;
}

#title{
	width:100%;
	height: 60px;
	margin-top: 0px;
	background-color:#5CC595;
	box-shadow: 0px 2px 4px #aaa;
}
#title h2{
	line-height: 60px;
	color: #fff;
	text-align: center;
}
#title button{
	position: absolute;
	top:80%;
	left:37.5%;
	background-color: #5CC595;
	width:25%;
	height:30px;
	border: 0px;
	border-radius: 5px;
	box-shadow: 0px 2px 4px #aaa;
	text-align: center;
	color: #fff;
	font-size: 18px;
	line-height: 21px;
	cursor: pointer;
}

#pageBody{
	position: absolute;
	width: 100%;
	height: 90%;
	top:10%;

}

#sidebar{
	position: absolute;
	width: 20%;
	height: 100%;
	left: 0;
	box-shadow: 2px 2px 4px #aaa;
	-moz-transition: width 0.5s; /* Firefox 4 */
	-webkit-transition: width 0.5s; /* Safari 和 Chrome */
	-o-transition: width 0.5s; /* Opera */
}

#content{
	position: absolute;
	width: 80%;
	height: 90%;
	top:10%;
	right: 0;
	-moz-transition: width 0.5s; /* Firefox 4 */
	-webkit-transition: width 0.5s; /* Safari 和 Chrome */
	-o-transition: width 0.5s; /* Opera */
}
</style>
<body>
	<div id="container">
		<div id="header"><img οnclick="change()" src="./images/hamburger.png" alt="" id="hamburger-icon"><img src="./images/more.png" alt="" id="more-icon"></div>
		<div id="pageBody">
			<div id="sidebar">
				<div id="title">
					<h2>Title</h2>
					<button>more</button>
				</div>
			</div>
			<div id="content">
			</div>
		</div>
	</div>
	<script>
		function change(){
			var sidebar=document.getElementById('sidebar');
			var content=document.getElementById('content');
			width_sidebar=sidebar.style.width ||sidebar.offsetWidth || sidebar.clientWidth;
			if(width_sidebar!='0px'){
			sidebar.style.width='0';
			content.style.width='100%';
			}
			else{
			sidebar.style.width='20%';
			content.style.width='80%';	
			}
		};
	</script>
</body>
</html></span>
这是sidebar平滑过渡效果,他们的状态改变不是用伪类hover,而是使用了js事件改变宽度,值得学习

<script setup> // import { h } from &#39;snabbdom&#39; import { onBeforeUnmount, ref, shallowRef } from &#39;vue&#39; // import { IButtonMenu } from &#39;@wangeditor/core&#39; import { Boot } from &#39;@wangeditor/editor&#39; import { Editor, Toolbar } from &#39;@wangeditor/editor-for-vue&#39; // 测试:第三方插件 // import withCtrlEnter from &#39;@wangeditor/plugin-ctrl-enter&#39; // Boot.registerPlugin(withCtrlEnter) // // 测试:多语言 // i18nChangeLanguage(&#39;en&#39;) // // 测试:注册 renderElem // function renderElemFn(elem, children) { // const vnode = h(&#39;div&#39;, {}, children) // type: &#39;paragraph&#39; 节点,即渲染为 <p> 标签 // return vnode // } // const renderElemConf = { // type: &#39;paragraph&#39;, // 节点 type ,重要!!! // renderElem: renderElemFn, // } // Boot.registerRenderElem(renderElemConf) // // 测试:注册插件 // function withCtrlEnter(editor) { // const { insertBreak } = editor // setTimeout(() => { // // beforeInput 事件不能识别 ctrl+enter ,所以自己绑定 DOM 事件 // const { $textArea } = DomEditor.getTextarea(newEditor) // $textArea.on(&#39;keydown&#39;, e => { // const isCtrl = e.ctrlKey || e.metaKey // if (e.keyCode === 13 && isCtrl) { // // ctrl+enter 触发换行 // editor.insertBreak() // } // }) // }) // const newEditor = editor // newEditor.insertBreak = () => { // const e = window.event // const isCtrl = e.ctrlKey || e.metaKey // // 只有 ctrl 才能换行 // if (isCtrl) { // insertBreak() // } // } // return newEditor // } // Boot.registerPlugin(withCtrlEnter) // 测试:注册 button menu // class MyButtonMenu { // constructor() { // // this.title = &#39;&#39;, // this.tag = &#39;button&#39; // } // getValue() { return &#39;&#39; } // isActive() { return false } // isDisabled() { return false } // exec(editor) { // console.log(editor) // // alert(&#39;menu1 exec&#39;) // } // } // const menuConf = { // key: &#39;my-menu-1&#39;, // menu key ,唯一。注册之后,需通过 toolbarKeys 配置到工具栏 // factory() { // return new MyButtonMenu() // }, // } // // 检查菜单是否已注册,避免重复注册 // if (!Boot.getMenuConfig(&#39;my-menu-1&#39;)) { // Boot.registerMenu(menuConf); // console.log(&#39;菜单注册成功&#39;); // } else { // console.log(&#39;菜单已存在,跳过注册&#39;); // } // console.log(1111111111) // 移到组件最外层,确保模块加载时只执行一次 class MyButtonMenu { constructor() { this.title = &#39;&#39;; // 必须有标题,否则按钮不显示 this.tag = &#39;button&#39;; } getValue() { return &#39;&#39;; } isActive() { return false; } isDisabled() { return false; } exec(editor) { // console.log(&#39;自定义菜单点击&#39;, editor); // editor.insertText(&#39;这是自定义菜单插入的内容&#39;); // 示例功能 } } const menuConf = { key: &#39;my-menu-1&#39;, factory() { return new MyButtonMenu(); }, }; // 核心:用try-catch捕获重复注册错误 try { Boot.registerMenu(menuConf); console.log(&#39;菜单注册成功&#39;); } catch (err) { if (err.message.includes(&#39;Duplicated key&#39;)) { console.log(&#39;菜单已注册,跳过重复注册&#39;); } else { console.error(&#39;菜单注册失败:&#39;, err); } } // 编辑器实例,必须用 shallowRef ,重要! const editorRef = shallowRef() // 内容 HTML const valueHtml = ref(&#39;<p>hello world</p>&#39;) // 编辑器配置 const editorConfig = { placeholder: &#39;请输入内容...&#39;, MENU_CONF: { insertImage: { checkImage(src) { console.log(&#39;image src&#39;, src) if (src.indexOf("http") !== 0) { return "图片网址必须以 http/https 开头"; } return true; }, }, } } // 工具栏配置 const toolbarConfig = { // toolbarKeys: [&#39;headerSelect&#39;, &#39;bold&#39;, &#39;my-menu-1&#39;], // excludeKeys: [], insertKeys: { index: 0, keys: &#39;my-menu-1&#39; } } // 编辑器回调函数 const handleCreated = (editor) => { console.log("created", editor); editorRef.value = editor // 记录 editor 实例,重要! // window.editor = editor // 临时测试使用,用完删除 } const handleChange = (editor) => { console.log("change:", editor.children); } const handleDestroyed = (editor) => { console.log(&#39;destroyed&#39;, editor) } const handleFocus = (editor) => { console.log(&#39;focus&#39;, editor) } const handleBlur = (editor) => { console.log(&#39;blur&#39;, editor) } const customAlert = (info, type) => { alert(`【自定义提示】${type} - ${info}`) } const customPaste = (editor, event, callback) => { console.log(&#39;ClipboardEvent 粘贴事件对象&#39;, event) // 自定义插入内容 editor.insertText(&#39;xxx&#39;) // 返回值(注意,vue 事件的返回值,不能用 return) callback(false) // 返回 false ,阻止默认粘贴行为 // callback(true) // 返回 true ,继续默认的粘贴行为 } // 及时销毁编辑器 onBeforeUnmount(() => { const editor = editorRef.value if (editor == null) return // 销毁,并移除 editor editor.destroy() }) const getHtml = () => { const editor = editorRef.value if (editor == null) return console.log(editor.getHtml()) } </script> <template> <!-- <div>--> <!-- <button @click="getHtml">获取 html</button>--> <!-- </div>--> <!-- <div style="border: 1px solid #ccc">--> <!-- <!– 工具栏 –>--> <!-- <Toolbar--> <!-- :editor="editorRef"--> <!-- :defaultConfig="toolbarConfig"--> <!-- style="border-bottom: 1px solid #ccc"--> <!-- />--> <!-- <!– 编辑器 –>--> <!-- <Editor--> <!-- v-model="valueHtml"--> <!-- :defaultConfig="editorConfig"--> <!-- @onChange="handleChange"--> <!-- @onCreated="handleCreated"--> <!-- @onDestroyed="handleDestroyed"--> <!-- @onFocus="handleFocus"--> <!-- @onBlur="handleBlur"--> <!-- @customAlert="customAlert"--> <!-- @customPaste="customPaste"--> <!-- style="height: 500px"--> <!-- />--> <!-- </div>--> <div class="editor-container"> <!-- 添加容器类名 --> <!-- 工具栏 --> <Toolbar :editor="editorRef" :defaultConfig="toolbarConfig" style="border-bottom: 1px solid #e5e7eb" /> <!-- 编辑器 --> <Editor v-model="valueHtml" :defaultConfig="editorConfig" @onChange="handleChange" @onCreated="handleCreated" @onDestroyed="handleDestroyed" @onFocus="handleFocus" @onBlur="handleBlur" @customAlert="customAlert" @customPaste="customPaste" /> </div> </template> <style src="@wangeditor/editor/dist/css/style.css"> /* 编辑器整体容器 */ .editor-container { border: 1px solid #e5e7eb; /* 浅灰色边框 */ border-radius: 8px; /* 圆角 */ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); /* 轻微阴影 */ overflow: hidden; /* 防止内部元素溢出 */ transition: box-shadow 0.2s ease; /* 阴影过渡效果 */ } .editor-container:hover { box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); /* hover时增强阴影 */ } /* 工具栏样式 */ .w-e-toolbar { background-color: #f9fafb !important; /* 工具栏背景色 */ border-bottom: 1px solid #e5e7eb !important; /* 底部边框 */ padding: 8px 12px !important; /* 内边距 */ } /* 工具栏按钮通用样式 */ .w-e-toolbar .w-e-menu { margin: 0 3px !important; /* 按钮间距 */ border-radius: 4px !important; /* 按钮圆角 */ transition: all 0.2s ease !important; /* 过渡效果 */ } .w-e-toolbar .w-e-menu:hover { background-color: #eef2f5 !important; /* 悬停背景色 */ transform: translateY(-1px) !important; /* 轻微上浮效果 */ } /* 自定义菜单按钮样式(my-menu-1) */ .w-e-toolbar [data-key="my-menu-1"] { background-color: #4f46e5 !important; /* 紫色背景(突出自定义按钮) */ color: white !important; /* 白色文字 */ border: none !important; } .w-e-toolbar [data-key="my-menu-1"]:hover { background-color: #4338ca !important; /* 深色hover效果 */ } /* 编辑区域样式 */ .w-e-text-container { height: 500px !important; /* 固定高度 */ padding: 16px !important; /* 内边距 */ background-color: white !important; /* 白色背景 */ } /* 编辑区域内容样式 */ .w-e-text-container p { margin: 0 0 12px 0 !important; /* 段落间距 */ line-height: 1.8 !important; /* 行高(提升可读性) */ font-size: 14px !important; /* 基础字体大小 */ color: #1f2937 !important; /* 文字颜色 */ } /* 编辑区域聚焦样式 */ .w-e-text-container:focus-within { outline: 2px solid rgba(79, 70, 229, 0.2) !important; /* 聚焦时边框高亮 */ } /* 工具栏割线样式 */ .w-e-toolbar .w-e-separator { background-color: #e5e7eb !important; /* 割线颜色 */ margin: 0 6px !important; /* 割线间距 */ } /* 响应式调整(小屏幕适配) */ @media (max-width: 768px) { .editor-container { border-radius: 4px; /* 小屏幕减小圆角 */ } .w-e-toolbar { padding: 4px 8px !important; /* 小屏幕减小内边距 */ } .w-e-text-container { height: 400px !important; /* 小屏幕减小编辑区高度 */ padding: 12px !important; } } </style>改一改让工具栏悬浮在上面,不会随着页面移动,不论页面滚轮怎么移动都保持在页面上方,右侧添加滚轮使页面可以移动,工具栏上面再搞一个头部,最左边是返回键,中间是AI笔记的标题,最右边是一个头像,点击头像会跳转到个人用户管理界面,头像左边有一个历史记录按钮,点击后会显示一个侧边栏,里面有AI笔记历史,历史记录先留一个按钮就行,头像也先留一个位置就行
最新发布
07-26
<think>我们有一个需求:在Vue项目中使用wangEditor,并实现以下功能: 1. 固定顶部工具栏:当页面滚动时,工具栏始终固定在顶部。 2. 自定义头部:在页面顶部添加一个头部区域,包含返回按钮、标题、历史记录按钮和用户头像。 3. 支持页面滚动和侧边栏显示。 分析: 1. wangEditor的工具栏固定:wangEditor默认工具栏是随着编辑器一起滚动的。要实现固定,我们可以将工具栏单独提取出来,并设置为固定定位(fixed或sticky)。 2. 自定义头部:我们需要在编辑器上方添加一个自定义的头部区域,同样固定定位,这样在滚动时头部和工具栏都会固定在顶部。 3. 侧边栏和滚动条:侧边栏可能是与编辑器并排的布局,我们可以使用flex布局来实现。 步骤: 1. 创建Vue组件,引入wangEditor。 2. 在组件中,我们将编辑器为两部:工具栏和编辑区域。通过wangEditor的配置,我们可以离工具栏和编辑区域。 3. 使用CSS将工具栏和自定义头部固定到顶部。 4. 设置编辑区域的高度,并确保其可以滚动。 5. 实现侧边栏布局。 注意:wangEditor v5版本支持离工具栏。 参考wangEditor文档:https://www.wangeditor.com/v5/for-frame.html#vue 具体实现: 1. 安装wangEditor: ```bash npm install @wangeditor/editor @wangeditor/editor-for-vue # 或 yarn add @wangeditor/editor @wangeditor/editor-for-vue ``` 2. 创建组件(例如:`RichTextEditor.vue`): ```vue <template> <div class="editor-container"> <!-- 自定义头部 --> <div class="custom-header"> <button class="back-button">返回</button> <div class="title">标题</div> <button class="history-button">历史记录</button> <div class="user-avatar"> <img src="path/to/avatar.jpg" alt="用户头像"> </div> </div> <!-- 工具栏 --> <div ref="toolbarRef" style="background-color: #f1f1f1;"></div> <!-- 编辑区域 --> <div ref="editorRef" style="height: calc(100vh - 120px);"></div> <!-- 侧边栏(根据需求添加内容) --> <div class="sidebar"> <!-- 侧边栏内容 --> </div> </div> </template> <script> import &#39;@wangeditor/editor/dist/css/style.css&#39; // 引入 css import { onBeforeUnmount, onMounted, ref, shallowRef } from &#39;vue&#39; import { Editor, Toolbar } from &#39;@wangeditor/editor-for-vue&#39; export default { components: { Editor, Toolbar }, setup() { // 编辑器实例,必须用 shallowRef const editorRef = ref(null) const toolbarRef = ref(null) const editor = shallowRef(null) // 模拟数据 const valueHtml = ref(&#39;<p>hello</p>&#39;) // 配置 const editorConfig = { placeholder: &#39;请输入内容...&#39;, // 其他配置... } // 组件挂载时 onMounted(() => { // 创建编辑器 editor.value = new Editor({ selector: editorRef.value, html: valueHtml.value, config: editorConfig, mode: &#39;default&#39;, // 或 &#39;simple&#39; }) // 创建工具栏 const toolbar = new Toolbar({ editor: editor.value, selector: toolbarRef.value, config: { // 工具栏配置 } }) }) onBeforeUnmount(() => { // 组件销毁时,销毁编辑器 editor.value.destroy() }) return { editorRef, toolbarRef, valueHtml, } } } </script> <style> .editor-container { display: flex; flex-direction: column; height: 100vh; position: relative; } .custom-header { position: sticky; top: 0; z-index: 100; display: flex; align-items: center; padding: 10px; background-color: white; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } .back-button, .history-button { padding: 5px 10px; background: #eee; border: none; cursor: pointer; } .title { flex: 1; text-align: center; font-weight: bold; } .user-avatar img { width: 30px; height: 30px; border-radius: 50%; } /* 工具栏固定 */ #toolbar-container { position: sticky; top: 50px; /* 根据自定义头部的高度调整 */ z-index: 99; background-color: white; } /* 侧边栏布局 */ .editor-container { display: flex; } .sidebar { width: 200px; background: #f8f8f8; height: calc(100vh - 120px); /* 减去头部和工具栏的高度 */ overflow-y: auto; } /* 编辑区域和工具栏区域 */ .editor-main { flex: 1; display: flex; flex-direction: column; } /* 调整结构,将工具栏和编辑区域放在一个容器中,侧边栏在另一边 */ </style> ``` 但是,上面的代码中,工具栏和编辑区域是离的,但是侧边栏和编辑区域是并排的。我们需要调整结构: 修改模板: ```vue <template> <div class="editor-layout"> <!-- 自定义头部 --> <div class="custom-header"> <!-- ... --> </div> <div class="main-content"> <!-- 侧边栏 --> <div class="sidebar"> <!-- 侧边栏内容 --> </div> <div class="editor-container"> <!-- 工具栏 --> <div ref="toolbarRef" class="toolbar-container"></div> <!-- 编辑区域 --> <div ref="editorRef" class="editor-content"></div> </div> </div> </div> </template> <style> .editor-layout { display: flex; flex-direction: column; height: 100vh; } .custom-header { position: sticky; top: 0; z-index: 100; /* ... 同上 ... */ } .main-content { display: flex; flex: 1; overflow: hidden; } .sidebar { width: 200px; background: #f8f8f8; overflow-y: auto; } .editor-container { flex: 1; display: flex; flex-direction: column; overflow: hidden; } .toolbar-container { position: sticky; top: 50px; /* 根据自定义头部的高度,如果头部高度是50px,则这里设置top:50px */ z-index: 99; background-color: white; } .editor-content { flex: 1; overflow-y: auto; padding: 10px; } </style> ``` 注意: 1. 自定义头部固定,所以使用`position: sticky; top:0;` 2. 工具栏也要固定,但位置应该在头部下方,所以设置`top: 头部高度`(假设头部高度为50px,则设置`top:50px`) 3. 编辑区域需要设置高度,并且可以滚动。 这样,当页面滚动时,头部和工具栏都会固定在顶部,编辑区域和侧边栏可以滚动。 但是,如果侧边栏内容很长,也需要滚动,我们可以给侧边栏设置`overflow-y: auto;`。 另外,需要根据实际头部高度调整工具栏的top值。 3. 关于历史记录按钮的功能:这需要你自己实现历史记录逻辑(比如记录编辑内容的变化),可以使用wangEditor的onChange事件来记录内容变化。 4. 返回按钮、用户头像等功能需要根据实际项目需求实现。 5. 注意:由于工具栏和编辑区域离,我们需要确保在销毁组件时,同时销毁工具栏和编辑器。 以上是一个基本的实现思路。根据实际需求,你可能还需要调整样式和布局。 相关问题: 1. 如何实现wangEditor的内容实时保存? 2. wangEditor如何插入自定义元素? 3. 在Vue中如何实现富文本编辑器的撤销和重做功能? 4. 如何优化wangEditor在Vue项目中的性能?</think>下面是在 Vue 中实现固定 wangEditor 工具栏和自定义头部的完整解决方案: ### 实现思路 1. **固定工具栏**:使用 wangEditor 的 `excludeKeys` 配置离工具栏和编辑区 2. **自定义头部**:创建独立组件实现标题栏功能 3. **布局结构**:使用 CSS Grid 实现侧边栏+主内容区的响应式布局 4. **滚动控制**:通过 `scrollIntoView` 实现平滑滚动 ### 完整实现代码 ```vue <template> <div class="editor-layout"> <!-- 自定义头部 --> <HeaderBar :title="pageTitle" @back="handleBack" @history="showHistory" /> <div class="main-container"> <!-- 侧边栏 --> <Sidebar :sections="sections" @navigate="scrollToSection"/> <!-- 编辑器区域 --> <div class="content-area"> <!-- 固定工具栏 --> <div ref="toolbar" class="fixed-toolbar"></div> <!-- 编辑区域 --> <div ref="editor" class="editor-content"></div> </div> </div> </div> </template> <script> import { onBeforeUnmount, onMounted, ref, shallowRef } from &#39;vue&#39; import &#39;@wangeditor/editor/dist/css/style.css&#39; import { Editor, Toolbar } from &#39;@wangeditor/editor-for-vue&#39; import HeaderBar from &#39;./HeaderBar.vue&#39; import Sidebar from &#39;./Sidebar.vue&#39; export default { components: { HeaderBar, Sidebar }, setup() { const toolbar = ref(null) const editor = ref(null) const editorInstance = shallowRef(null) const pageTitle = ref(&#39;文档编辑&#39;) const sections = ref([ { id: &#39;section1&#39;, title: &#39;第一章&#39; }, { id: &#39;section2&#39;, title: &#39;第二章&#39; } ]) // 初始化编辑器 onMounted(() => { // 创建编辑器实例 editorInstance.value = new Editor({ selector: editor.value, config: { placeholder: &#39;请输入内容...&#39;, scroll: false, // 禁用编辑器自带滚动 excludeKeys: [&#39;fullScreen&#39;] // 排除不需要的工具栏项 } }) // 创建工具栏实例 new Toolbar({ editor: editorInstance.value, selector: toolbar.value, config: { excludeKeys: [&#39;insertImage&#39;, &#39;group-video&#39;] // 自定义工具栏项 } }) }) // 滚动到指定部 const scrollToSection = (id) => { const element = document.getElementById(id) if (element) element.scrollIntoView({ behavior: &#39;smooth&#39; }) } // 返回按钮处理 const handleBack = () => { console.log(&#39;返回操作&#39;) } // 历史记录处理 const showHistory = () => { console.log(&#39;显示历史记录&#39;) } // 组件销毁时销毁编辑器 onBeforeUnmount(() => { if (editorInstance.value) editorInstance.value.destroy() }) return { toolbar, editor, pageTitle, sections, scrollToSection, handleBack, showHistory } } } </script> <style> .editor-layout { display: flex; flex-direction: column; height: 100vh; overflow: hidden; } .main-container { display: grid; grid-template-columns: 250px 1fr; flex: 1; overflow: hidden; } .content-area { display: flex; flex-direction: column; overflow: hidden; } .fixed-toolbar { position: sticky; top: 0; z-index: 100; background: white; box-shadow: 0 2px 10px rgba(0,0,0,0.1); } .editor-content { flex: 1; overflow-y: auto; padding: 20px; border: 1px solid #e8e8e8; } </style> ``` ### HeaderBar.vue 组件 ```vue <template> <header class="custom-header"> <button class="back-btn" @click="$emit(&#39;back&#39;)"> <i class="icon-back"></i> </button> <div class="title">{{ title }}</div> <div class="header-right"> <button class="history-btn" @click="$emit(&#39;history&#39;)"> <i class="icon-history"></i> </button> <div class="user-avatar"> <img :src="avatarUrl" alt="用户头像"> </div> </div> </header> </template> <script> export default { props: { title: String }, data() { return { avatarUrl: &#39;https://avatar.example.com/user.jpg&#39; } } } </script> <style> .custom-header { display: flex; align-items: center; padding: 0 20px; height: 60px; background: #fff; box-shadow: 0 2px 10px rgba(0,0,0,0.1); z-index: 1000; } .back-btn, .history-btn { width: 40px; height: 40px; border: none; background: none; cursor: pointer; } .title { flex: 1; text-align: center; font-size: 18px; font-weight: bold; } .header-right { display: flex; align-items: center; } .user-avatar img { width: 40px; height: 40px; border-radius: 50%; object-fit: cover; } </style> ``` ### 关键实现说明 1. **工具栏固定原理**: - 使用 `excludeKeys` 配置离工具栏和编辑区 - 通过 CSS `position: sticky` 实现固定定位 - 禁用编辑器自带滚动条(`scroll: false`) 2. **响应式布局**: ```css .main-container { display: grid; grid-template-columns: 250px 1fr; } ``` 使用 CSS Grid 实现侧边栏和主内容区的响应式布局[^1] 3. **滚动控制**: ```javascript const scrollToSection = (id) => { document.getElementById(id).scrollIntoView({ behavior: &#39;smooth&#39; }) } ``` 使用原生 DOM API 实现平滑滚动定位[^1] 4. **组件化结构**: - `HeaderBar`:处理头部导航逻辑 - `Sidebar`:管理文档章节导航 - 主组件:集成编辑器和布局控制 ### 注意事项 1. 使用 `shallowRef` 存储编辑器实例避免响应式代理问题 2. 组件销毁时务必调用 `editor.destroy()` 3. 工具栏固定高度需考虑头部高度避免重叠 4. 移动端需额外添加视口 meta 标签 ```html <meta name="viewport" content="width=device-width, initial-scale=1.0"> ``` ### 优化建议 1. **性能优化**: - 使用 `IntersectionObserver` 实现章节自动高亮[^1] - 对编辑器内容启用节流保存 - 使用 Vue 的 `keep-alive` 缓存组件状态 2. **功能扩展**: ```javascript // 添加自定义按钮 toolbarConfig.insertKeys = { index: 5, // 插入位置 keys: [&#39;customBtn&#39;] } ``` 3. **响应式处理**: ```css @media (max-width: 768px) { .main-container { grid-template-columns: 1fr; } .sidebar { display: none; /* 移动端隐藏侧边栏 */ } } ``` [^1]: vue-scrollactive-基于视口中的当前部在菜单项中添加活动类,单击菜单项时也会滚动到该部。 vue-intersect-将Vue组件添加到Vue组件或HTML元素的Vue组件。 vue-scrollmonitor-一个Vue插件,通过支持多种浏览器来监视视口内元素的可见性状态(使用provide / inject,因此兼容vue@2.2.x) vue-stroll -Vue.js 2.x的一个很棒的CSS3表滚动效果组件。 navscroll-js-滚动时突出显示菜单项,并且单击菜单项时还会滚动到某个部。用作vue组件,vue指令或与vanilla js一起使用。 vue-scrollwatch-一个轻巧的插件,可检测滚动事件,在元素进入视口时自定义回调,使用&#39;vue指令&#39;暴露&#39;scrollTo&#39;API滚动至特定元素。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值