모바일 브라우저에서 글 내용에 따라 자동으로 늘어나는 textarea 만들기 2

안녕하세요

제가 앞에 작성한 “모바일 브라우저에서 글 내용에 따라 자동으로 늘어나는 textarea 만들기” 는 글을 작성한 만큼 textarea의 크기가 늘어납니다. 하지만 작성한 글을 지워서 내용이 줄어들었을 때 textarea의 크기는 줄어들지 않고 계속 커진 상태로 남아 있습니다.

이점을 수정해서 글 내용이 많아질 때는 textarea의 크기가 커지고 글 내용이 줄어들었을 때는 textarea의 크기도 작아지도록 만들어봤습니다. 이것을 구현하기 위해 어떻게 해야할지 생각이 잘 안떠올랐는데 검색을 해보니 구현하신 분이 있어서 그 분의 아이디어를 그대로 가져와서 만들었습니다. 그 분의 글은 http://james.padolsey.com/javascript/jquery-plugin-autoresize/ 입니다.

textarea의 크기를 늘리는 기능은, 글 내용이 길어지면 textarea의 scrollHeight 값이 커지기 때문에 이 크기에 따라 textarea의 높이(height)를 조절해 주는 방식으로 만들수 있었지만 textarea의 크기를 줄이는 기능은 이 방법을 사용할 수 없었습니다. textarea의 높이가 글 내용 높이보다 작아서 스크롤바가 생기는 상황이라면 글 내용의 많고 적음에 따라 scrollHeight 값이 변하지만, 이미 textarea의 높이를 글 내용이 많아졌을 때에 맞게 늘렸었기 때문에 이 상태에서 글자를 지워서 글 내용 높이를 줄여도 scrollHeight의 값은 변하지 않게 되어 textarea 높이를 글 내용 높이에 맞게 줄여줄 기준값으로 사용할 수 없게 되기 때문입니다.

이 것을 해결하기 위해 제가 참고한 http://james.padolsey.com/javascript/jquery-plugin-autoresize/ 에서는 textarea의 clone을 만드는 방법을 사용하고 있었습니다. clone으로 만든 textarea는 사용자에게는 안보이도록 positin:absolute; top:0; left:-9999; 처리를 한 다음 사용자에게 보이는 진짜 textarea에 글씨가 입력될 때마다 clone textarea에도 그대로 글이 입력되게 합니다. 그리고 진짜 textarea의 높이 조절을 clone textarea의 scrollHeight 값을 가지고 조절하는 방식입니다.
(그런데 제가 참고한 사이트에서 clone을 사용한다는 아이디어만 참고하고 나머지 코드는 참고를 안해서 제가 만든 버전은 오류가 좀 있을 수도 있을 것 같습니다.)

제가 말씀으로 설명드려서 좀 복잡한데 소스코드를 보시면 이해가 되실 것 같습니다.

// textarea의 id가 textarea인 경우를 가정해서 #textarea 사용
(function() {

	var textarea = $('#textarea'),
		originHeight = textarea.height(),
		originClientHeight = textarea[0].clientHeight,
		clone = textarea.clone(),
		extraHeight = parseInt(textarea.css('fontSize')),
		timer, content, cloneScrollHeight;

	clone
		.removeAttr('id')
		.removeAttr('name')
		.css({
			position: 'absolute',
			top: 0,
			left: -9999,
			overflow: 'hidden'
		}).appendTo('body');

	textarea.focus(function() {

		timer = setInterval(function() {
			content = textarea.val();
			clone.val(content);
			cloneScrollHeight = clone[0].scrollHeight;

			if (originClientHeight < cloneScrollHeight) {
				textarea.css('height', cloneScrollHeight + extraHeight);
			} else if (originClientHeight === cloneScrollHeight) {
				textarea.css('height', originHeight);
			}
		}, 100);

	});

	textarea.blur(function() {
		clearInterval(timer);
	});

})();

데모를 http://codefactory.kr/lab/autogrowshrink_textarea.html 에 올려놓았습니다. 필요하신 분은 한번 확인해보세요..^^

  • http://www.google.com/ Marni

    Great airtlce, thank you again for writing.

  • http://www.facebook.com/ryuzr 류인상

    안녕하세요.
    코드를 보다가 30번째줄에 = 이 3개가 있던데 머 오류없이 동작은 잘되는데 혹시
    오타인가여? 아니면 = 3개가 맞는건가염~ 제가 잘 몰라서여…

    • codefactory

      안녕하세요
      아 네, 그 부분은 오타는 아닙니다. 그 부분을 == 로 바꾸셔도 아마 작동하실 것입니다.

      == 와 === 모두 같은지 안같은지 비교하는 연산자인데 그 정확도에 차이가 있습니다. 자바스크립트가 아닌 다른 언어들도 == 와 === 를 구분하는 것으로 알고 있는데요, 자바스립트의 경우에 대해서만 말씀을 드리면,

      == 는 양쪽의 값이 같은지만 비교하고, === 는 양쪽의 값고 데이터 type까지 같이 비교합니다. == 의 경우 강제 type변환을 해서 같은지 비교합니다. 이게 설명이 좀 긴데요, https://github.com/rwldrn/idiomatic.js 를 한 번 보시면 자세히 나와 있습니다.

      저는 30번째 줄에서 좀더 정교한 비교를 하라는 의미에서 === 를 사용했는데, 이번 경우에는 originClientHeight 와 cloneScrollHeight 모두 Number type으로 데이터 type이 같기 때문에 == 를 사용해도 차이가 없게 됩니다.

      감사합니다.

  • 도라쓰

    감사합니다. 유용하게 잘 쓰겠습니다~ ^^

    • codefactory

      감사합니다..^^