در حال بارگذاری ...

Creating Enhanced Textarea0:00

All right, let's review a couple other Composition API gotchas. So let's do this. In my home view, let's create a big text area that maybe we will enhance. All right, let's have a look. So if I switch to the browser, yeah, here's what we get. So real quick, let's do this. Pardon the inline styling, but I'll say width is 100% and height is maybe 300 pixels. Okay, so now imagine you're building something like a comment form, but maybe it doesn't justify a full dedicated WYSIWYG. Instead, you just want some nice to haves.

Accessing DOM with Refs2:02

So let's prevent that default behavior. Okay, so yeah, this is something you might prepare, but let's figure out how we can integrate it into a component. So the first step is, well, we need some kind of textArea. All right, well, we have one here. So let's start by giving it a ref, and we'll just call it textArea, simple enough. And then let's create that up here. Let textArea equal a ref. All right, and this is pretty cool. If you ever want to access a specific element or DOM node in your template, just give it

All right, and this is pretty cool. If you ever want to access a specific element or DOM node in your template, just give it a ref, provide any name you want, and then create a variable that's equal to a null ref. So yeah, if we take a look at this real quick, console, actually, this might trip you up. So real quick, if I were to say console.log(textArea.value), I think that's probably going to be null. So let's open up console, and yeah, give it a refresh, and that's equal to null. And that's because at the point we logged that, the textArea hasn't yet mounted to the page. So you can see if we actually delay that, one more time, there it is.

Using onMounted Hook3:01

the page. So you can see if we actually delay that, one more time, there it is. So now if we dig down, we do have access to the textArea. So yeah, otherwise, if you need to use it, you could say, well, listen for onMounted. So yeah, when we were using the options API, we would just create a method on that object called mounted. But remember, with the composition API, we are importing all of the options we require, basically, including hooks like mounted. Okay, so now, if I were to console.log textArea.value, at this point, the textArea has mounted to the page.

Okay, so now, if I were to console.log textArea.value, at this point, the text area has mounted to the page. So if we clear this out, refresh, yeah, now I do have access to it. And yeah, it can get a little tricky here with .value. Because it's a form element, I would have to do something like this, .value.value, to grab the actual value of the text area. A little tricky there. But anyways, let's get back to work. So the next step is to figure out how to make all of this work. First up, as we discussed, we should use textArea.value to access the node.

So the next step is to figure out how to make all of this work. First up, as we discussed, we should use textArea.value to access the node. Next, I only want to listen for a keydown event after the component has mounted. So I will bring back mounted, and paste that in. Next within here, and just for a moment, let's just create a quick variable that is textArea.value. And that way, I can update all of this. Okay, so yeah, one step at a time, hide the sidebar, switch back, and let's see if it works. div, tab, oh, and it's working. Hi there.

Handling Tab Key Events4:54

Tab, three, four, it works. Okay, so the next step is to clean this up. So first, instead of manually calling addEventListener, I could instead, if we scroll down, do it here. Listen for a keydown event, and then why don't we create a method called onKeyDown. Okay, so now we can create that. Let's begin by removing the onMounted hook, and then I could grab all of this here, and wrap it within a function called onKeyDown, which will accept the event. Okay, and I'll paste that in. Okay, so now we can get rid of the addEventListener, because we're already doing that at the point

and it tabs me away from the text area. Okay. Well, we could add it there, but we could also do it down here again. We can chain these. So .prevent. It's kind of cool. Listen for a key down, specifically the tab key, and as part of that, prevent the default behavior for that particular event. Another option, if you want, is we don't actually need a ref here, so have a look at this. We could listen for the key down event and call tabPress, and then within here, we could

Another option, if you want, is we don't actually need a ref here, so have a look at this. We could listen for the keyDown event and call tabPress, and then within here, we could of course grab the textArea by saying e.target. So give me the target of the event, and if I'm pressing the tab key within a textArea, the target of the event is the textArea node. So we could just as easily access it like this. And then maybe we can rename this t variable to textArea. Yeah. And actually, we don't listen for a mounted hook either. So now we just have a simple function.

Extracting Reusable Component8:04

Maybe if you want to use it elsewhere in the project, the next step is to extract a dedicated component. So we'll do that now. In my components directory, we'll create a new one. And why don't we call it, well, not just textArea. What is unique about it? Tabable. It's a tabable textArea. All right. So let's switch back.

All right. So let's switch back to the home view. We can now import our tabable component. So what is it? Components, tabable text area. Okay. And now I can use it here. And yeah, if I wanted to, I could paste in any custom styles here. Don't forget when you pass any attributes that aren't props to a custom component, they will basically cascade down to the root element of that component.

Okay. So let's see if we can make this work. Let comment equal a ref that defaults to an empty string. Or actually, let's give it a starting value. Test value. Okay. So if we did everything right, the initial value for this tabable text area should be test value, but it won't be. So if I switch back and give it a refresh, nope, we're not doing anything with that. Okay.

Implementing v-model Support10:38

So if I switch back and give it a refresh, nope, we're not doing anything with that. Okay. Well, we actually discussed how to make v-model work with custom components a number of episodes ago, but let's do a little recap. The first step is to define a prop. So again, with the options API, you would just create a props object, and we learned about using that key modelValue. But instead, when we're using script setup, we're going to use this macro here, defineProps. And we'll do it here.

props. And we'll do it here. And what we pass here, this object is exactly the same object that you would have passed in the options API. Okay. So modelValue, and that will be of type string. Okay. So now at the very least, we have access to the initial value. Come back. Let's open up view, go down to our tabable text area.

Come back. Let's open up view, go down to our tabable text area. And yeah, notice modelValue is accepting that string. The next step is to, of course, use it. Okay. Well, down here, we could say, let's make this self-closing. And then I can say v-text equals modelValue. All right. Does that work? Yes, it does.

Does that work? Yes, it does. But now what about the reverse? When I type into it, I want to update that. And of course, right now, we're not doing that. So once again, yeah, that's not working. Okay. And again, all of this should be a recap from a number of episodes ago. The next step is to listen for when the user types and emit an event. This is how we keep the two in sync.

The next step is to listen for when the user types and emit an event. This is how we keep the two in sync. So let's do another one here. When you lift up a key, why don't we call a method update, and then I will probably inline this function, but one step at a time. All right. We'll create a function update, and this needs to emit an update event. So when we were working with the options API, yeah, we did something like this, where it takes the shape of update, the name of the property, the default is modelValue, and then we give it whatever the string is here.

it takes the shape of update, the name of the property, the default is model value, and then we give it whatever the string is here. In this case, we could do something like E, and that would be the value of the text area, right? But yeah, when we're in script setup, we can't do this emit. So yeah, this is another case with script setup where we're doing the same thing, but it's a little bit different in terms of how we prepare it. So we're going to define our emits, or in other words, the events that this component will emit. And in this case, if this is the event name, we'll pass it in up here.

will emit. And in this case, if this is the event name, we'll pass it in up here. And yeah, this is generally considered a good practice. We haven't yet reviewed this, but for any events that your components will emit, it's optional, but it's a good practice to declare them here. Okay. So now that will return to us an emit function that we can then call. Like this. Scroll on down, and all we do is change this like so. emit, we give it the name, and everything should be the same here.

So yeah, a little bit confusing. This is one of the more confusing parts of working with view components, but trust me, once you understand it, you'll have this. So now our model value is updated, and the comment is as well. And you'll see if I switch over to the events tab, yeah, notice as I type in here, we're firing all of these component events, or component level events. And don't forget, I just want to make this crystal clear. This syntax here, it needs to be this. So you can't just say anything you want. Update model value.

So you can't just say anything you want. Update modelValue. No, it needs to take this exact shape. Okay. Next if you want, we talked about this, we could inline this entirely. So I could just do that instead if you'd like to get rid of a function, and that would be fine. And yeah, I'll let you take a look at this. Here is our simple component. To allow for v-model, we define a prop with a name of modelValue.

Here is our simple component. To allow for v-model, we define a prop with a name of modelValue. Next we define our emits with update:modelValue, which is required to make v-model on custom components work. Next we have a single function that will handle a tab press. And remember, any variables or functions you declare in script setup will always be available in your template. And then next we register just a handful of events. And notice real quick, we split up keydown and keyup because if we want to prevent the tab key sending you away from the text area, we couldn't do that with keyup.

And notice real quick, we split up keyDown and keyUp because if we want to prevent the tab key sending you away from the textarea, we couldn't do that with keyUp. It would need to be done as part of keyDown. So that's why we do that. But next, after you've pressed a key and we keyUp, we can emit the new value of the textarea. And I think that'll do it. So yeah, if we were to test this out, I often do setTimeout just to make sure everything's in sync. Maybe after two seconds, let's set comment.value to it works.

in sync. Maybe after two seconds, let's set comment.value to it works. Yeah, hopefully this should all work. Give it a refresh. One, two, and everything is in sync. And now you have a slightly enhanced text area. Pretty cool. So the key things to learn in this lesson is the necessity for these little custom little compiler macros, whatever you want to call them. One for defineProps and one for defineEmits.

compiler macros, whatever you want to call them. One for defineProps and one for defineEmits. And remember, those are only accessible within script setup. Once everything is compiled down, these will be replaced behind the scenes. So again, to say it two times, you can only use these within script setup.

v-model for Custom ComponentsdefinePropsdefineEmits

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟