截取HTML字符串 允许忽略HTML标志不计

本文介绍了一个PHP函数,用于截取包含HTML标签的字符串,并确保不会切断HTML标签,同时可选择性地添加省略号。
<?php
/**
* 截取HTML字符串 允许忽略HTML标志不计
*
* Author:学无止境
* Email:xjtdy888@163.com
* QQ: 339534039
* Home:http://www.phpos.org
* Blog:http://hi.baidu.com/phps
*
* 转载请保留作者信息


* @param 要截取的HTML $str
* @param 截取的数量 $num
* @param 是否需要加上更多 $more
* @return 截取串
*/
function phpos_chsubstr_ahtml($str,$num,$more=false)
{
    
$leng=strlen($str);
      
if($num>=$leng)      return $str;
    
$word=0;
    
$i=0;                        /** 字符串指针 **/
    
$stag=array(array());        /** 存放开始HTML的标志 **/
    
$etag=array(array());        /** 存放结束HTML的标志 **/
    
$sp = 0;
    
$ep = 0;
      
while($word!=$num)
      {

          
if(ord($str[$i])>128)
          {
            
//$re.=substr($str,$i,3);
            $i+=3;
            
$word++;
          }
          
else if ($str[$i]=='<')
          {
              
if ($str[$i+1== '!')
              {
                
$i++;
                  
continue;
              }

              
if ($str[$i+1]=='/')    
              {
                
$ptag=&$etag ;
                
$k=&$ep;
                
$i+=2;
              }
              
else                    
              {
                
$ptag=&$stag;
                
$i+=1;
                
$k=&$sp;
              }

              
for(;$i<$leng;$i++)        
              {
                  
if ($str[$i== ' ')
                  {
                    
$ptag[$k= implode('',$ptag[$k]);
                    
$k++;
                      
break;
                  }
                  
if ($str[$i!= '>'
                  {
                    
$ptag[$k][]=$str[$i];
                      
continue;
                  }
                  
else                
                  {
                    
$ptag[$k= implode('',$ptag[$k]);
                    
$k++;
                      
break;
                  }
              }
            
$i++;
              
continue;
          }
          
else
          {
            
//$re.=substr($str,$i,1);
            $word++;
            
$i++;
          }
      }
      
foreach ($etag as $val)
      {
        
$key1=array_search($val,$stag);
          
if ($key1 !== false)          unset($stag[$key]);
      }
      
foreach ($stag as $key => $val)
      {
          
if (in_array($val,array('br','img'))) unset($stag[$key1]);
      }
    
array_reverse($stag);
    
$ends = '</'.implode('></',$stag).'>';
    
$re = substr($str,0,$i).$ends;
      
if($more)    $re.='...';
      
return $re;
}

$str=<<<EOF
<h3>What is the <acronym>GNU</acronym> pr<a><a><a>oject?</h3>
<p>The <acronym>GNU</acronym> Project was launched in 1984 to develop a complete Unix-like operating system which is <a href="http://www.gnu.org/philosophy/free-sw.html">free software</a>: the <acronym>GNU</acronym> system. Variants of the <acronym>GNU</acronym> operating system, which use the kernel called Linux, are now widely used; though these systems are often referred to as &ldquo;Linux&rdquo;, they are more accurately called <a href="http://www.gnu.org/gnu/linux-and-gnu.html">GNU/Linux systems</a>. </p>
<p><acronym>GNU</acronym> is a recursive acronym for &ldquo;GNU's Not Unix&rdquo;; it is pronounced <em>guh-noo</em>, approximately like <em>canoe</em>.</p>
<h3>What is Free Software?</h3>
<p>&ldquo;<a href="http://www.gnu.org/philosophy/free-sw.html">Free software</a>&rdquo; is a matter of liberty, not price. To understand the concept, you should think of &ldquo;free&rdquo; as in &ldquo;free speech&rdquo;, not as in &ldquo;free beer&rdquo;.</p>
<p>Free software is a matter of the users
' freedom to run, copy, distribute, study, change and improve the software. More precisely, it refers to four kinds of freedom, for the users of the software:</p>
<ul>
      
<li>The freedom to run the program, for any purpose (freedom 0). </li>
      
<li>The freedom to study how the program works, and adapt it to your needs (freedom 1). Access to the source code is a precondition for this. </li>
      
<li>The freedom to redistribute copies so you can help your neighbor (freedom 2). </li>
      
<li>The freedom to improve the program, and release your improvements to the public, so that the whole community benefits (freedom 3). Access to the source code is a precondition for this. </li>
</ul>
<h3>What is the Free Software Foundation?</h3>
<p>The <a href="http://www.fsf.org/">Free Software Foundation</a> (<abbr title="Free Software Foundation">) is the principal organizational sponsor of the Project. The receives very little funding from corporations or grant-making foundations, but relies on support from individuals like you. </abbr>) is the principal organizational sponsor of the Project. The receives very little funding from corporations or grant-making foundations, but relies on support from individuals like you. </p>
<p>Please consider helping the <abbr>by , or by . If you use Free Software in your business, you can also consider or as a way to support the . </abbr>by , or by . If you use Free Software in your business, you can also consider or as a way to support the . </p>
<p>The <acronym>GNU</acronym> project supports the mission of the <abbr>to preserve, protect and promote the freedom to use, study, copy, modify, and redistribute computer software, and to defend the rights of Free Software users. We support the on the Internet, , and the unimpeded by private monopolies. You can also learn more about these issues in the book . </abbr>to preserve, protect and promote the freedom to use, study, copy, modify, and redistribute computer software, and to defend the rights of Free Software users. We support the on the Internet, , and the unimpeded by private monopolies. You can also learn more about these issues in the book . </p>
<!--
Keep link lines at 
72 characters or lynx will break them poorly.
Obviously
, we list ONLY the most useful/important URLs here.
Keep it short and sweet
: 3 lines and 2 columns is already enough
--><!-- BEGIN GNUmenu -->
EOF;
echo phpos_chsubstr_ahtml($str,800);
?>
 
<think>我们正在使用Vue 3,并且要使用vue-quill-editor(一个富文本编辑器)并添加字符限制功能。 根据问题,我们需要实现:当用户输入超过一定字符数时,阻止输入并提示。 思路: 1. 我们可以利用Quill编辑器的API来监听文本变化。 2. 在变化事件中,获取当前编辑器的内容(文本或HTML)并计算长度(注意:如果限制的是纯文本字符数,则应该获取文本内容;如果限制的是HTML字符数,则获取HTML字符串)。 3. 如果当前内容长度超过限制,则阻止输入(可以通过删除多余输入来实现)并给出提示。 另外,我们需要注意,由于vue-quill-editor在Vue 3中对应的包可能是`@vueup/vue-quill`,这里我们假设使用的是这个包(因为原来的vue-quill-editor并支持Vue 3)。 步骤: 1. 安装并引入Quill编辑器(如果尚未安装)。 2. 在组件中注册并使用Quill编辑器。 3. 给Quill编辑器绑定一个ref,以便在Vue中访问编辑器实例。 4. 在mounted(或onMounted)生命周期中,通过ref获取编辑器实例,并添加文本变化事件监听器(text-change事件)。 5. 在事件处理函数中,计算当前内容的长度,并与最大长度比较。 6. 如果超过了最大长度,则撤销最后的输入(通过编辑器的API)并弹出提示。 但是,需要注意的是,直接撤销输入可能会造成用户体验佳,而且Quill的撤销操作可能会带来其他问题。另一种方法是,我们在输入时检查,如果超过最大长度,则阻止输入(通过删除多余字符)。同时,我们还可以在界面上显示当前字符数和最大字符数。 为了更好的用户体验,我们可以: - 显示当前字符数和最大字符数(如:1000/2000)。 - 当超过最大字符数时,将超过部分的文本截断,并提示用户。 具体实现: 假设我们限制的是纯文本的字符数(即去除HTML标签后的文本长度)。 我们可以使用以下方法: - 获取编辑器的纯文本内容:`editor.getText()`(注意:getText()返回的字符串末尾会有一个换行符,我们需要去除这个换行符再计算长度?或者计算长度时减去这个换行符?实际上,我们可以通过trim()去除两端空白,但这里换行符在末尾,通常我们会输入那么多换行,所以直接计算长度,然后减去1?这样并稳妥,因为用户可能输入很多换行。所以,我们考虑在计算长度时,如果末尾有换行符,我们不计算它?但这样也合理,因为用户输入的换行符也是字符。因此,我们建议按照实际获取的文本长度来计算,包括所有空白符。但注意,getText()返回的字符串末尾有一个换行符,这是Quill默认的,我们可以忽略它吗?或者我们在设置内容时,避免这个换行符? 实际上,Quill编辑器在初始化时,默认就会有一个换行符(所以长度为1)。因此,我们在设置最大长度时,可能需要考虑这个因素。或者,我们可以采用另一种方式:使用editor.getContents()获取Delta内容,然后计算文本长度(遍历所有操作),但这样复杂。所以,我们直接使用getText(),然后计算长度。 但是,我们需要注意的是,getText()返回的字符串包括编辑器中的所有文本,包括换行符和空格。所以,我们应该按照实际字符数来计算。 步骤: 1. 在data中定义两个变量:maxLength(最大字符数,比如2000)和currentLength(当前字符数)。 2. 在模板中显示当前字符数和最大字符数。 3. 监听编辑器的text-change事件,在事件处理程序中更新currentLength,并检查是否超过maxLength。 但是,text-change事件在每次变化时都会触发,包括格式化文本(如加粗)也会触发,但格式化会增加字符数,所以我们需要在事件中获取最新的纯文本长度。 事件处理函数: function onTextChange(delta, oldContents, source) { let text = this.quill.getText().trim(); // 去除两端空白,但注意:如果我们需要计算空白,就trim // 或者我们trim,因为用户可能会输入空格,也是字符 let textLength = text.length; // 但是,Quill默认在最后有一个换行符,会导致长度为1(即使没有内容)。所以,我们可以判断如果最后一个是换行符,则减去1?但这样也准确,因为用户可能输入换行符。 // 因此,我们考虑:在初始化时,如果没有内容,则长度应该是0,但getText()返回\n,长度为1。所以,我们要避免这个初始换行符被计入。 // 另一种做法:在初始化后,我们设置编辑器的内容为空字符串,这样就会有初始换行符。但这样可能会破坏Quill的默认行为。 // 实际上,我们可以忽略这个初始换行符?或者我们在计算时,如果整个编辑器只有一个换行符,则视为0。但这样复杂。 // 所以,我们采取:在用户输入时,我们计算的长度包括换行符,那么我们的最大长度也应该包括换行符。即用户输入一个换行符,占用1个字符。 // 因此,我们直接计算text.length,包括所有字符。 // 检查是否超过最大长度 if (textLength > this.maxLength) { // 超出,我们需要将内容截断到最大长度 // 注意:我们能直接操作DOM,而是通过Quill的API // 由于我们已经超出了,我们需要将超出部分的输入撤销 // 我们可以通过设置编辑器的内容为之前的旧内容(即未超出之前的内容)来实现 // 但是,text-change事件中,我们无法撤销当前操作(因为已经发生了),所以我们可以使用quill.updateContents来撤销最后一次操作?或者我们记录上一次未超出的内容。 // 另一种做法:我们可以在每次变化时,如果超出,则设置编辑器的内容为之前保存的未超出的内容(即上一次未超出的内容)。我们需要一个变量来保存最后一次未超出的内容(oldContent)。 // 但是,这样可能会丢失用户的其他操作(比如格式化)。 // 因此,我们采用:在超出时,我们删除超出部分的字符。具体做法是:先获取当前内容,然后截取字符串(注意:是纯文本,但如果我们直接操作纯文本,会丢失格式)。所以,我们需要操作Delta。 // 思路:获取当前的Delta,然后遍历每个操作,计算每个操作插入的文本长度,直到达到最大长度,然后删除剩余的操作。 // 但是,这样实现复杂。 // 简单做法:我们通过quill.getText()得到当前文本,然后截取maxLength长度的子串,然后重新设置编辑器的纯文本?但是这样会丢失格式。 // 因此,我们需要一个既能保留格式又能截断文本的方法。 // 参考:我们可以使用quill.getContents()获取当前的Delta,然后遍历这个Delta,计算每个操作的文本长度,然后重建一个Delta,直到达到最大长度。 // 由于实现复杂,我们可以考虑使用第三方库(如quill-delta)来处理Delta,或者自己实现。 // 为了简化,我们可以只处理纯文本,考虑格式?但这样友好。 // 或者我们可以接受:在超过最大长度时,我们只保留之前的内容(即撤销最后一次输入)。我们可以使用quill.history.undo(),但这样会撤销整个最后一次操作(可能包括格式变化),而且可能撤销多个字符(如果用户是粘贴一段文本)。 // 所以,我们需要精确控制:只删除超出部分的字符。 // 这里我们深入复杂实现,而是采用:当超出时,我们通过quill.deleteText(maxLength, textLength)来删除从maxLength到textLength的字符。 // 但是,注意:deleteText的两个参数是索引(开始索引和结束索引)。开始索引是maxLength,结束索引是textLength(即当前文本长度)。这样就能删除超出部分。 // 但是,这个索引是按照纯文本的索引吗?是的,因为Quill的deleteText方法接受的是文本索引(注意:这个索引是按照纯文本的索引,包括格式信息)。 // 所以,我们可以: this.quill.deleteText(this.maxLength, textLength); // 但是,这样删除后,光标会停留在最后,我们需要将光标移动到最后。 // 同时,由于我们删除了部分文本,所以currentLength会变成maxLength,因此我们需要更新currentLength。 // 但是,注意:textChange事件可能会被再次触发(因为deleteText操作会触发新的text-change事件)。所以,我们需要避免递归触发。 // 解决方法:在事件处理函数中,如果我们执行了deleteText,则设置一个标志,避免再次执行。 // 或者,我们可以在执行deleteText之前,先移除事件监听,执行完后再添加回来。 // 或者,我们用一个变量来锁定,避免重复处理。 // 我们来修改:在onTextChange函数中,如果已经处于截断过程中,则直接返回。否则,当我们进行截断时,设置一个标志,然后执行删除,执行完后重置标志。 // 但是,由于Vue是响应式的,我们可以使用一个变量来标记是否正在处理。 // 另外,我们还需要注意,删除操作会触发新的text-change事件,所以我们需要避免重复处理。 // 因此,我们使用一个标志位:isTruncating,初始为false。 // 在事件处理函数开始,如果isTruncating为true,则直接返回。 // 否则,当需要截断时,设置isTruncating为true,然后执行删除操作,然后更新currentLength(设置为maxLength),然后弹出提示。然后,在下一事件循环(或删除操作完成后)重置isTruncating?但注意,删除操作会立即触发新的text-change事件,所以我们在新事件中检测到isTruncating为true就直接返回,会再次处理。 // 这样我们就可以避免递归。 // 但是,我们这里使用Vue 3,我们可以用ref来存储这个标志。 // 步骤: // a. 定义const isTruncating = ref(false); // b. 在onTextChange函数中,首先判断if (isTruncating.value) return; // c. 当需要截断时: // isTruncating.value = true; // this.quill.deleteText(this.maxLength, textLength); // // 删除完成后,更新currentLength // this.currentLength = this.maxLength; // // 然后,我们需要在下一个微任务中重置isTruncating,以便后续正常处理 // this.$nextTick(() => { // isTruncating.value = false; // }); // // 或者使用Promise.resolve().then(() => { isTruncating.value = false; }); // d. 同时,给出提示:字符数超过限制,已自动截断。 } else { this.currentLength = textLength; } } 但是,上述方法在删除文本时,可能会因为索引错误而导致删除准确(因为Quill的索引是基于文本的,但我们的文本中可能包含换行符等,索引是连续的)。 注意:quill.getText()返回的字符串是包含所有字符(包括换行)的连续字符串,所以索引是连续的。因此,使用deleteText(maxLength, textLength)可以删除超出部分。 然而,这种方法会丢失被删除部分的格式。但这是可避免的,因为我们只能保留前maxLength个字符。 另一种思路:在用户输入时,如果输入后总长度超过maxLength,则阻止输入(即让用户输入最后一个字符)。这样,我们可以在用户输入每个字符时检查。但是,对于粘贴操作,可能一次输入多个字符,我们仍然需要删除多余的。 因此,我们采用上述删除多余字符的方法。 但是,我们还需要注意,如果用户是从最后输入,而是在中间插入文本,可能会导致超出,这时我们删除的位置可能是用户输入的位置,而是从maxLength开始删除直到末尾。这样会导致用户插入位置之后的文本被删除。所以,我们需要考虑光标位置吗? 实际上,我们只关心总长度,所以无论用户在哪里插入,只要总长度超出,我们就删除超出部分(从maxLength位置开始删除后面的所有字符)。这样,用户可能会发现插入位置后面的内容被删除了。这虽然有些粗暴,但保证了总长度超过限制。 因此,我们按照上述方法实现。 代码结构(Vue 3 Composition API): 1. 引入Quill编辑器组件,并注册。 2. 在模板中使用Quill编辑器,并绑定ref。 3. 在setup中,定义maxLength(假设为2000),currentLength(ref(0)),isTruncating(ref(false)),quillEditor(ref(null))用于引用编辑器实例。 4. 在onMounted中,获取Quill实例(quillEditor.value.getQuill()),然后监听text-change事件。 5. 在text-change事件处理函数中,实现上述逻辑。 但是,注意:在Vue 3中,我们使用`@vueup/vue-quill`,它的Quill组件通过`ref`获取到的实例有一个`getQuill()`方法,返回Quill实例。 另外,我们还需要注意,编辑器初始化可能需要时间,所以我们在onMounted中确保编辑器已经初始化。 示例代码: 注意:以下代码为示例,可能需要根据实际调整。 步骤: 1. 安装依赖: npm install @vueup/vue-quill@next quill 2. 在组件中: <template> <div> <QuillEditor ref="quillEditor" ... /> <div>当前字数:{{ currentLength }} / {{ maxLength }}</div> </div> </template> <script> import { QuillEditor } from '@vueup/vue-quill' import '@vueup/vue-quill/dist/vue-quill.snow.css'; import { ref, onMounted } from 'vue'; export default { components: { QuillEditor }, setup() { const quillEditor = ref(null); // 用于引用QuillEditor组件实例 const maxLength = 2000; const currentLength = ref(0); const isTruncating = ref(false); // 防止递归 onMounted(() => { // 获取Quill实例 const quill = quillEditor.value.getQuill(); // 监听text-change事件 quill.on('text-change', () => { if (isTruncating.value) return; // 获取当前文本 const text = quill.getText().trim(); // 注意:这里我们使用trim()去除前后空白,但这样计算的长度包括前后空白。如果希望去除,则去掉trim()。 // 但是,注意:如果去除,那么Quill默认的末尾换行符会被计入。这里我们去除,计算实际长度(包括所有字符)。 // 重新计算:去除空白 const textFull = quill.getText(); // 注意:quill.getText()返回的字符串最后有一个换行符,这个换行符是Quill自动添加的(为了光标在最后一行时能够继续输入),但我们应该忽略它,因为它也是用户内容的一部分(如果用户输入了多个换行符,那么就会有多个换行符)。所以,我们直接计算textFull的长度。 const length = textFull.length - 1; // 减去最后一个换行符?为什么?因为Quill总是在最后加一个换行符。但是,如果用户输入了多个换行符,那么最后就有多个换行符,这样减去1就准确了。 // 实际上,这个换行符是Quill维护的,我们应该计入。因此,我们可以考虑减去最后一个换行符(如果有)。 // 但是,更合理的做法是:我们使用quill.getLength()方法,它返回的是编辑器内容的长度(包括所有格式标记和内容)。注意:这个方法返回的长度是包括格式标记的,所以比纯文本长度大? // 实际上,quill.getLength()返回的是编辑器内部表示的字符数(包括格式标记和内容),并是我们想要的纯文本长度。 // 因此,我们使用textFull.length,并忽略最后一个换行符(Quill自动添加的)?这样很难,因为Quill会自动添加换行符,但用户也可能输入换行符。 // 所以我们还是按照textFull.length来计算,包括最后一个换行符。这样,初始状态(空编辑器)时长度为1(只有一个换行符)。如果我们希望初始为0,那么我们可以减去1。 // 这里,我们决定:在计算长度时,减去1(忽略Quill自动添加的最后一个换行符)。这样,初始状态为0。 const textLength = textFull.length - 1; currentLength.value = textLength; if (textLength > maxLength) { // 开始截断 isTruncating.value = true; // 删除超出部分:从maxLength位置删除到textLength(这里textLength是减去1后的,所以我们在删除时,需要加上1?因为textFull.length比textLength大1) // 实际上,textFull.length = textLength + 1,所以我们要删除从maxLength到textFull.length-1(即textLength)的部分?对,textFull.length-1就是textLength(我们上面减去了1)。所以,我们在删除时,应该删除从maxLength到textFull.length-1(即textLength)的字符?但注意,textFull.length-1等于textLength,所以删除的区间是[maxLength, textLength](长度为textLength - maxLength)。 // 但是,在删除时,我们使用的索引是基于textFull(原始字符串)的,所以我们能使用textLength(因为textLength=textFull.length-1)。所以,我们使用: // start: maxLength, end: textFull.length - 1 // 但是,textFull.length - 1 就是整个字符串的最后一个字符(换行符)的前一个?对,索引是从0到textFull.length-1。 // 所以,我们要删除的是:从maxLength开始,到textFull.length-1(包括)的字符。这样删除的字符数就是 (textFull.length - 1 - maxLength) + 1 = textFull.length - maxLength 个字符。 // 但是,我们删除后,Quill会自动在最后加一个换行符,所以删除后textFull.length会变成maxLength+1(因为最后还有一个换行符)。这样,我们计算长度时又会减去1,得到maxLength。 quill.deleteText(maxLength, textFull.length - 1); // 删除后,更新currentLength currentLength.value = maxLength; // 提示 // 使用ElMessage或其他提示方式,这里省略 console.warn(`内容长度能超过${maxLength}个字符`); // 使用nextTick重置标志 setTimeout(() => { isTruncating.value = false; }, 0); } }); }); return { quillEditor, currentLength, maxLength }; } }; </script> 注意:上述代码中,我们减去1的方式可能并准确,因为Quill总是在最后维护一个换行符。因此,另一种做法是:我们去处理这个换行符,而是将maxLength设置为比实际显示的最大字符数多1(即允许的最大字符数+1)?这样,当用户输入达到最大字符数时,加上最后的换行符,总长度为最大字符数+1,但我们允许。然后,在显示当前字符数时,我们显示为当前长度-1。 但是,这样会令人困惑。所以,我们采用:在计算长度时,我们始终减去1(即忽略Quill自动添加的最后一个换行符)。这样,显示给用户的最大长度就是maxLength,而用户输入的字符数(包括换行符)最多为maxLength(因为我们减去1后等于maxLength,那么实际长度是maxLength+1,其中1是自动换行符)。 因此,在事件处理函数中,我们计算当前长度:textFull.length - 1。 当用户输入的内容(包括换行符)达到maxLength+1(即textFull.length == maxLength+1)时,我们计算的当前长度为maxLength(满足条件),但如果我们允许用户再输入一个字符,那么textFull.length变为maxLength+2,当前长度计算为maxLength+1,这时就超出,需要删除。 删除时,我们删除从maxLength到textFull.length-1(即maxLength+1)的部分(删除长度为1的字符)。删除后,textFull.length变为maxLength+1(因为删除后还有自动换行符),我们再计算长度:maxLength+1-1 = maxLength,符合。 所以,这个逻辑是自洽的。 但是,我们还需要考虑编辑器初始状态:当编辑器内容为空时,textFull是'\n',长度为1,计算的长度为0。 因此,我们按照这个逻辑实现。 另外,我们还可以在界面上显示当前字符数和最大字符数。 注意:如果用户输入的是富文本(包括图片等非文本内容),那么我们上面的方法只计算纯文本的长度。如果图片也要计入,那么我们需要单独考虑。但一般来说,字符限制只针对文本。所以,我们这里考虑图片。 如果要求图片等也占用一定的字符数(比如一张图片等价于100个字符),那么就需要更复杂的计算。 根据我们的需求,我们只针对文本字符数进行限制。 因此,按照上述实现即可。 但是,由于Quill的text-change事件在每次变化时都会触发,包括格式变化,所以性能上可能会有一些影响,但通常可以接受。 最后,我们还可以考虑使用防抖来优化性能(但文本输入时,我们通常需要实时响应,所以推荐)。 总结:在Vue 3中,我们可以通过监听Quill编辑器的text-change事件,计算当前纯文本长度(减去Quill自动添加的最后一个换行符),如果超出限制,则删除超出部分。 代码示例见上。 注意:由于实际项目可能使用选项式API,这里使用了组合式API,但思路相同。 另外,我们也可以使用watch来监听编辑器内容,但text-change事件更直接。 相关问题: 1. 如何为vue-quill-editor添加字数统计功能? 2. 在Vue 3中,如何获取vue-quill-editor的实例? 3. 如何阻止用户在富文本编辑器中输入超过指定长度的内容? 4. Quill编辑器中自动添加的换行符会影响字数统计吗?如何处理? 因此,我们可以生成以下相关问题: §§相关问题§§ 1. 在Vue 3中,如何监听vue-quill-editor的内容变化? 2. 如何避免在Quill编辑器的text-change事件处理函数中递归触发事件? 3. 除了纯文本长度,如何计算富文本编辑器中的内容长度(包括图片等非文本内容)? 4. 如何优化富文本编辑器的性能,特别是在实时计算字符数时? </think>在 Vue 3 中为 `vue-quill-editor` 添加字符限制功能,可通过以下步骤实现: ### 解决方案 1. **监听编辑器内容变化** 使用 Quill 的 `text-change` 事件监听内容变化,计算当前字符数: ```javascript import { ref, onMounted } from 'vue'; import { QuillEditor } from '@vueup/vue-quill'; const quillRef = ref(null); const charLimit = 500; // 最大字符数 const currentChars = ref(0); onMounted(() => { const quill = quillRef.value.getQuill(); quill.on('text-change', () => { const text = quill.getText().trim(); // 获取纯文本(HTML标签) currentChars.value = text.length; }); }); ``` 2. **超出限制时阻止输入** 在 `text-change` 事件中判断字符数,超出时删除多余内容: ```javascript quill.on('text-change', () => { const text = quill.getText().trim(); currentChars.value = text.length; if (currentChars.value > charLimit) { // 计算需删除的字符数 const delta = quill.getContents(); const deleteIndex = charLimit - currentChars.value; quill.deleteText(charLimit, deleteIndex); // 删除超限部分 ElMessage.warning(`最多允许输入 ${charLimit} 个字符`); // 提示 } }); ``` 3. **显示字符统计(可选)** 在模板中添加字符计数器: ```html <template> <QuillEditor ref="quillRef" /> <div :class="{ 'text-red': currentChars > charLimit }"> {{ currentChars }} / {{ charLimit }} </div> </template> ``` ### 关键说明 - **纯文本统计**:`quill.getText()` 获取纯文本内容,避免 HTML 标签影响计数。 - **防递归处理**:在删除内容时,Quill 会再次触发 `text-change`,但 `deleteText()` 操作会导致递归,因删除后字符数立即低于阈值。 - **性能优化**:直接操作 Quill 的 Delta 对象(`getContents()`)精准删除超限内容,而非重置整个编辑器[^1]。 ### 示例代码 ```html <template> <div> <QuillEditor ref="quillRef" /> <div :class="{ 'text-red': currentChars > charLimit }"> {{ currentChars }} / {{ charLimit }} </div> </div> </template> <script setup> import { ref, onMounted } from 'vue'; import { QuillEditor } from '@vueup/vue-quill'; import { ElMessage } from 'element-plus'; // 或使用其他提示库 const quillRef = ref(null); const charLimit = 500; const currentChars = ref(0); onMounted(() => { const quill = quillRef.value.getQuill(); quill.on('text-change', () => { const text = quill.getText().trim(); currentChars.value = text.length; if (currentChars.value > charLimit) { quill.deleteText(charLimit, currentChars.value - charLimit); ElMessage.warning(`字符数超过限制`); } }); }); </script> ``` ### 注意事项 1. **富文本处理**:若需统计带格式文本(如保留换行符),改用 `quill.root.innerHTML` 并计算长度(需注意 HTML 实体编码影响)。 2. **全局混入谨慎性**:如需跨组件复用,可将逻辑封装为 Composable,避免全局混入导致污染第三方组件[^1]。 3. **粘贴内容处理**:监听 `paste` 事件预处理粘贴内容,防止大量文本绕过限制: ```javascript quill.root.addEventListener('paste', (e) => { const pastedText = e.clipboardData.getData('text/plain'); if (pastedText.length + currentChars.value > charLimit) { e.preventDefault(); ElMessage.warning('粘贴内容超出字符限制'); } }); ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值