You 2022-06-23 18:55:14 阅读数:746
Based on the previous study , End use Vue-CLI The scaffold realizes TodoList The effect of the case is shown in the figure below :
Here are some requirements for the case :
The final effect is as follows :
Reference material : Novice tutorial JavaScript Higher order
JavaScript Object constructors in
function Person(name, age) {
this.name = name;
this.age = age;
}
var me = new Person("uni",22);
var myGirl = new Person("who", 22);
stay JavaScript You cannot add a new attribute to an instance object that already has a constructor in
For example, add an attribute hobby Show interest
Error model :
Person.hobby = " having dinner ";
Correct demonstration : ( Modify the original object declaration )
function Person(name, age, hobby) {
this.name = name;
this.age = age;
this.hobby = hobby;
}
1. prototype Inherit
be-all JavaScript All objects will come from a prototype( Prototype object ) Inherit properties and methods in :
such as JS Some self-contained objects :
Empathy , We defined Person Objects will also start from Person.prototype Inherit properties and methods .
all JavaScript The objects in are all located at the top of the prototype chain Object
Example , This is similar to Java All classes in the language are Object Subclasses of , There are Object Class toString()
Method .
JavaScript Object has a chain that points to a prototype object . When trying to access the properties of an object , It doesn't just search for the object , It also searches for the prototype of the object , And the prototype of the object , Search up one by one , Until you find a property that matches a name or you reach the end of the prototype chain ( namely Object).
In short , Whether it's JS Built in Date object , Array object , It's our custom Person Objects are from Object.prototype Inherit .
2. adopt prototype Add properties and methods
Applicable scenario :
The application case :
Person.prototype.hobby= " having dinner ";
function Person(first, last, age, eyecolor) {
this.name = name;
this.age = age;
}
Person.prototype.hobby = function() {
return this.name + " My hobby is eating ";
};
Specific cases :
So let's define one Person The constructor of the object , Only name and age Two properties , Create a based on the constructor uni object , When the button is clicked, the object will be prototype The prototype object adds a new property and a new method , And then through alert Print out :
The specific implementation code is as follows ( The file format is .html):
<!DOCTYPE html>
<head>
<h1> Test content </h1>
<button onclick="test(this)"> Initialize object </button>
</head>
<body>
<script type="text/javascript"> function Person(name, age){
this.name = name this.age = age } let uni = new Person('uni', 22) function test(btn){
// Get the upper level h1 label let h1 = btn.previousElementSibling // adopt prototype Add attribute Person.prototype.hobby = " having dinner " Person.prototype.showName = function(){
return " I am a : " + this.name } // return JSON Format test content h1.innerHTML = JSON.stringify(uni) // Print objects to the console console.log(uni) // Accessing prototype properties through objects alert(uni.showName(), uni.hobby) } </script>
</body>
</html>
Running effect :
Click the initialize object button , The pop-up window shows the object passing through prototype Set methods and properties
Click OK , The contents of the object will be in JSON The format is displayed in h1 title , As shown in the figure below
according to Vue Officially introduced : see
Every Vue Instances are created through a series of initialization processes —— for example , Data monitoring needs to be set 、 Compiling templates 、 Mount the instance to DOM And update when the data changes DOM etc. .
At the same time, some functions called life cycle hooks will be run in this process , This gives users the opportunity to add their own code at different stages .
It may be described in more detail in the English version : see
Every Vue Component instances go through a series of initialization steps when they are created
for example , It needs to set up data observation 、 Compiling templates 、 Load the instance to DOM, And update when data changes DOM.
meanwhile , It also runs functions called lifecycle hooks , Give users the opportunity to add their own code at a specific stage .
Vue The life cycle of is shown in the figure below :
According to the official introduction , Lifecycle hook (Hooks) It is the function represented by the red line circle in the above figure , It is essentially a function that will be executed at a specified stage .
When implementing this case , We mainly use three hook functions , Namely
Reference material : Video material
Before we passed vue Created multiple components , Each component has the relationship between upper and lower level calls , So according to the new demand , Now there is the problem of data communication between components , For example, after clicking Edit ,TodoItem The component needs to pass the edited information to App Components , Because the data is stored in App Medium , In order to maintain Vue Provided MVVM Model , We try not to modify the parent component directly in the introduced child component App in props Data transferred .
Vue Each component of is VueComponent Instance object of , According to the knowledge of the prototype chain , Their __proto__
The attribute points to Vue Of a prototype object , So you can do it Vue Data sharing among multiple components .
( The following figure is taken from the video )
The more important equation in the figure :
VueComponent.prototype.__proto__ === Vue.prototype
Equal to t r u e true true
Be careful : there VueComponent and Vue All prototype objects , Instead of instance objects .
The core idea of data communication : Provide a Vue Components , Deposit in Vue.prototype Secondary specialized for data communication .
In the introduction of Vue Of JS Code file
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
beforeCreate(){
Vue.prototype.$bus = this
}
}).$mount('#app')
Here we go through beforeCreate() Hook to define Vue Prototype variables for ,$bus
, Value is Vue Instance object itself , In this case ,Vue Inside Vue Component The component instance object can access $bus
, there $bus
A bus called a global event .
Next, summarize the usage of the following global event bus :
new Vue({
...
// Define... In the hook function
beforeCreate(){
Vue.prototype.$bus = this
},
})
$bus$
Binding custom events , The callback of the event remains A The component itself .methods(){
update(data) {
... }
}
...
mounted(){
this.$bus.$on('xxxx', this.update)
}
this.$bus.$emit('xxx', data )
Vue2 Of $emit
and $on
Next, I will make a supplement .
We can use the existing JS plug-in unit , such as pubsub To achieve this kind of message publishing and subscription .
stay Vue2 In the data communication of each component of , In order to ensure the smooth transmission of data , Usually, messages need to be defined in advance between two components .
A message is usually a function , One party is responsible for defining the received function parameters and the implementation logic of the function ( Message subscribers ), The other party is responsible for specifying the function to be called , And incoming data ( Message publisher ).
// Install the publish and subscribe plug-ins : npm i pubsub-js
// Subscribe to news ( Return a message ID)
const pubsubId = pubsub.subscribe(' Message name ', Callback function ( Message name , Message parameters ))
// Release the news
pubsub.publish(' Message name ', Message parameters )
// Unsubscribe ( According to the information released ID)
pubsub.unsubscribe(pubsubId)
Besides using pubsub.js
Beyond plug-in , We can also go through Vue2 Of $emit and $on To achieve
vm.$on( event, callback )
Parameters :
effect :
Listen for custom events on the current instance . Events can be caused by vm.$emit Trigger . The callback function receives all the extra parameters of the incoming event trigger function .
Example :
// Subscribe to news
vm.$on('test', function (msg) {
console.log(msg)
})
// Release the news
vm.$emit('test', 'hi')
// => "hi"
vm.$emit( eventName, […args] )
Parameters :
effect : Trigger events on the current instance . Additional parameters are passed to the listener callback .
In addition to binding events $on
outside , And the unbinding incident $off
vm.$off( [event, callback] )
Parameters :
usage :
Remove custom event listener
If no parameters are provided , The remove all The event monitor of
If only events are provided , Then remove the event all The monitor for
If both events and callbacks are provided , Only remove the listener of this callback .
Here we will use the idea of global event bus mentioned earlier , We passed it before props
To pass on the parameters , It is usually used to receive variables or functions passed from the parent component , After having a global bus , You can go directly through VueComponent The prototype in the component object $bus
, All component objects can be obtained $bus
Value , Then you can subscribe or publish messages through it .
there $bus
It's essentially Vue object , because Vue Prototypes between components all point to Vue Example of , and Vue Object also points to its Vue example , So the same Vue Object Vue Components can communicate with each other through it .
transition yes Vue2 Built in components , It is usually used to set up a single HTML Animation of labels , Multiple label animations require the use of transition-group
effect :
<transition>
The element as a single element / Transition effects of components .<transition>
Will only apply the transition effect to the contents of its package , Without extra rendering DOM Elements , It doesn't appear at the component level that can be checked .
Official cases :
<!-- Simple elements -->
<transition>
<div v-if="ok">toggled content</div>
</transition>
<!-- Dynamic components -->
<transition name="fade" mode="out-in" appear>
<component :is="view"></component>
</transition>
<!-- Event hooks -->
<div id="transition-demo">
<transition @after-enter="transitionComplete">
<div v-show="ok">toggled content</div>
</transition>
</div>
<script type="text/javascript"> new Vue({
... methods: {
transitionComplete: function (el) {
// Pass in 'el' This DOM Element as parameter . } } ... }).$mount('#transition-demo') </script>
The part used in this case :
<template>
<nav>
<transition appear>
<input name="edit" v-show="todoObj.isEdit" ref="inputTodo" class="come" type="text">
</transition>
</nav>
</template>
<script> import 'animate.css' export default {
name: 'TodoItem', methods: {
... }, // introduce TodoBody From the todoObj props: ['todoObj'], } </script>
<style scoped> .come{
animation: fromRight linear 1s; } .to{
animation: fromRight linear 1s reverse; } /* Vue Automatically assign name by edit and flag The entry and exit styles of */ .edit-enter-active{
animation: fromRight linear 1s; } .edit-leave-active{
animation: fromRight linear 1s reverse; } /* Vue Animation */ @keyframes fromRight{
from{
transform: translateX(100px); opacity: 0; } to{
transform: translateX(0px); opacity: 100; } } </style>
In the above case input The label is only in todoObj.isEdit The value is true When it shows , For easy viewing Vue2 Built in transition Use of components , I have neglected all the other irrelevant contents , Here you can see -enter-active
and -leave-active
Is a fixed class name , Represents the animation loaded when entering and leaving respectively , Apart from these two , also Other things like :
among v You can change to <transition>
Inside the label name attribute , For example, in the above case , It's located name="edit" The label of .
transition-group Is an upgraded version of the previous component , It can animate multiple components at the same time .
It and transition
The biggest difference is , All in this tab HTML label All need to specify key .
Elements as multiple elements / Transition effects of components . Rendering a real DOM Elements . Default rendering , Can pass tag attribute Configure which element should be rendered .
Official case ( It's obvious here , It's better for setting up lists 、 Styles like tables ):
<transition-group tag="ul" name="slide">
<li v-for="item in items" :key="item.id">
{
{ item.text }}
</li>
</transition-group>
Installation commands
npm install animate.css --save
Use : In any component <script>
Import css
import 'animate.css'
Defined in the animation tab :
<template>
<transition name="animate__animated anmate__bounce" enter-active-class="animate__backInDown" leave-active-class="animate__backOutUp" appear>
<div id="app">
<h1><img src="./assets/logo.png"> be based on Vue2 Of TodoList Case study </h1>
<TodoHeader></TodoHeader>
<TodoBody></TodoBody>
<TodoFooter></TodoFooter>
</div>
</transition>
</template>
<script> import TodoHeader from './components/TodoHeader.vue' import TodoBody from './components/TodoBody.vue' import TodoFooter from './components/TodoFooter.vue' import 'animate.css' export default {
name: 'App', components: {
TodoHeader, TodoBody, TodoFooter}, } </script>
<style scoped> h1{
text-align: center;} img{
width: 50px; height: 50px;} #app{
width: 600px; margin: 0 auto; } </style>
The configuration of styles is also placed in <transition>
On the label , It is mainly the following three sentences :
name="animate__animated anmate__bounce"
enter-active-class="animate__backInDown"
leave-active-class="animate__backOutUp"
First name The value is fixed , According to the characteristics of this plug-in , Only set fixed for the label name, To configure animate.css Relevant animation will be effective .
Ahead enter-active-class This is actually Vue2 Properties provided , After all <transition>
yes Vue2 A built-in component , For more attributes, please refer to : see , The following class name is provided by the plug-in , You can find it on the official website ( The effect of the official website is very good , There is animation after clicking ):
HTML5 web Storage , A ratio cookie Better local storage .
The two objects that the browser stores data are :
localStorage - For long-term preservation of data across the site , Saved data has no expiration time , Until removed by hand .
sessionStorage - Used to temporarily save the same window ( Or tabs ) The data of , The data will be deleted after closing the window or tab .
When we're browsing the web , Most websites will keep some information in our browsers . For example, visit Baidu
Here you can see , When I want to search for something , It will prompt for search history , Where is the search history stored ?
yes Cookie still Session ?
In fact, neither of them is , It's stored in HTML5 Supported by localStorage In the object .
We can view it directly through the browser debugging tool :
Can pass JavaScript To set up the data store , In this way, some input information of the user can be recorded , More suitable for search engines .
In the use of web Before storage , Check whether the browser supports localStorage and sessionStorage
( These are both JS Built in objects for , stay JS Can be called directly in the code )
if(typeof(Storage)!=="undefined")
{
// Yes ! Support localStorage sessionStorage object !
// Some codes .....
} else {
// I'm sorry ! I won't support it web Storage .
}
localStorage
Common commands (sessionStorage similar )
// Storage
localStorage.setItem("name", "uni");
// obtain
localStorage.getItem("name");
// Removing a single
localStorage.removeItem("name");
// Delete all
localStorage.clear()
// Get an index of Key
localStorage.key(index);
Tips : localStorage The key / Value pairs are usually stored as strings , You can convert the format according to your own needs .
Object storage can be done through JSON Type to format , Put all the to-do items (Array type ) adopt JS Store in localStorage
// save Array
localStorage.setItem("todoList", JSON.stringify(todoList));
// Read Array
const todoList = localStorage.getItem("todoList, JSON.parse(todoList));
Project structure :
Scaffold default generated configuration , There is no change
const {
defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
})
Program entry file , This build Vue example , At the same time, specify the components that communicate with each other $bus
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
beforeCreate(){
Vue.prototype.$bus = this
}
}).$mount('#app')
<template>
<transition name="animate__animated anmate__bounce" enter-active-class="animate__backInDown" leave-active-class="animate__backOutUp" appear>
<div id="app">
<h1><img src="./assets/logo.png"> be based on Vue2 Of TodoList Case study </h1>
<TodoHeader @fnAddTodo="fnAddTodo" ></TodoHeader>
<TodoBody :todoList="todoList"></TodoBody>
<TodoFooter :todoList="todoList"></TodoFooter>
</div>
</transition>
</template>
<script> import TodoHeader from './components/TodoHeader.vue' import TodoBody from './components/TodoBody.vue' import TodoFooter from './components/TodoFooter.vue' export default {
name: 'App', data(){
return {
todoList: JSON.parse(localStorage.getItem('todoList')) || [] } }, methods: {
// function : Add a new to-do fnAddTodo(todoObj){
this.todoList.unshift(todoObj) }, // function : Switch the status of the to-do list fnCheckTodo(id){
this.todoList.forEach((todoObj) => {
if(id === todoObj.id) todoObj.done = !todoObj.done }) }, // function : Delete to-do fnDeleteTodo(id){
this.todoList = this.todoList.filter(todoObj => todoObj.id !== id) }, // function : Status of batch operation to-do items fnUpdateCheckTodo(done){
this.todoList.forEach((todoObj) => todoObj.done = done) }, // function : Clear completed to DOS fnClearFinishedTodo(){
if(confirm(' Are you sure you want to delete ?')) this.todoList = this.todoList.filter((todoObj) => !todoObj.done) }, // function : Update the contents of the to-do list fnUpdateTodo(id, title){
this.todoList.forEach((todoObj) => {
if(todoObj.id === id) todoObj.title = title }) } }, mounted(){
this.$bus.$on('fnCheckTodo', this.fnCheckTodo) this.$bus.$on('fnUpdateTodo', this.fnUpdateTodo) this.$bus.$on('fnDeleteTodo', this.fnDeleteTodo) this.$bus.$on('fnClearFinishedTodo', this.fnClearFinishedTodo) this.$bus.$on('fnUpdateCheckTodo', this.fnUpdateCheckTodo) }, beforeDestroy(){
this.$bus.$off('fnCheckTodo') this.$bus.$off('fnUpdateTodo') this.$bus.$off('fnDeleteTodo') this.$bus.$off('fnUpdateTodo') this.$bus.$off('fnClearFinishedTodo') this.$bus.$off('fnUpdateCheckTodo') }, components: {
TodoHeader, TodoBody, TodoFooter}, // Monitor attribute values , If there is any change, put it into the local cache watch: {
todoList: {
deep: true, handler(value){
localStorage.setItem('todoList', JSON.stringify(value)) } } } } </script>
<style scoped> h1{
text-align: center;} img{
width: 50px; height: 50px;} #app{
width: 600px; margin: 0 auto; } </style>
<template>
<div>
<label for="add"> To do list </label>
<input id="add" v-model="title" @keydown.enter="add" placeholder=" Please enter the task title , Press enter to confirm ">
<button @click="add"> add to </button>
</div>
</template>
<script> // Third party Library npm i nanoid import {
nanoid} from 'nanoid' export default {
name: 'TodoHeader', data() {
return {
title: '' } }, methods: {
// add to Todo add(){
if(!this.title.trim()) return alert(' Tips : The entered to-do list cannot be empty !') // encapsulation Todo object const todoObj = {
id: nanoid(), title: this.title, done: false } // Call callback function this.$emit('fnAddTodo', todoObj) // Empty this.title = '' } } } </script>
<style scoped> div{
background: gray; padding: 20px; font-size: 1.2em; } button, input{
font-size: 1.1em; } button{
float: right; } </style>
<template>
<div>
<ul>
<li v-for="todoObj in todoList" :key="todoObj.id">
<TodoItem :todoObj="todoObj"></TodoItem>
</li>
</ul>
</div>
</template>
<script> import TodoItem from './TodoItem.vue' export default {
name: 'TodoBody', components: {
TodoItem}, props: ['todoList'] } </script>
<style scoped> div{
background: pink; padding: 20px; font-size: 1.1em; } ul{
list-style: none; padding-left: 0px; } </style>
<template>
<nav v-show="totalTodoList">
<input type="checkbox" v-model="isAll">
Completed {
{ totalFinishedTodo }} / All {
{ totalTodoList }}
<button @click="clearFinishedTodo"> Cleanup completed </button>
</nav>
</template>
<script> export default {
name: 'TodoFooter', props: ['todoList'], methods: {
clearFinishedTodo(){
this.$bus.$emit('fnClearFinishedTodo') } }, // Compute properties computed:{
// Calculate completed to DOS totalFinishedTodo(){
return this.todoList.reduce((pre, todoObj) => pre + (todoObj.done ? 1 : 0), 0) }, // All to-do items totalTodoList(){
return this.todoList.length }, isAll: {
// Default check condition of select all button : All to-do items have been completed get(){
return this.totalTodoList > 0 && this.totalFinishedTodo == this.totalTodoList }, set(value){
return this.$bus.$emit('fnUpdateCheckTodo',value) } } } } </script>
<style scoped> nav{
background: greenyellow; padding: 20px; font-size: 1.1em; } input{
height: 1.5em; width: 1.5em; } button{
float:right; font-size: 1.1em; } </style>
<template>
<nav>
<input type="checkbox" :checked="todoObj.done" @change="handleCheckTodo(todoObj.id)">
<span name="flag" v-show="!todoObj.isEdit">{
{ todoObj.title }}</span>
<transition appear>
<input name="edit" v-show="todoObj.isEdit" ref="inputTodo" class="input come" type="text" :value="todoObj.title" @blur="handleSaveTodo(todoObj, $event)">
</transition>
<button @click="handleDeleteTodo(todoObj.id)"> Delete </button>
<button @click="handleEditTodo(todoObj)"> edit </button>
</nav>
</template>
<script> import 'animate.css' export default {
name: 'TodoItem', methods: {
handleCheckTodo(id){
this.$bus.$emit('fnCheckTodo', id) }, handleDeleteTodo(id){
if(confirm(' Are you sure you want to delete Id by [' + id + '] To-do list for ?')) this.$bus.$emit('fnDeleteTodo', id) }, handleEditTodo(todoObj){
// Determine whether the to-do list has isEdit attribute if(!Object.hasOwn(todoObj, 'isEdit')){
// If not, it is dynamically set to true this.$set(todoObj, 'isEdit', true) } else{
// If yes, set it directly to true todoObj.isEdit = true } // Focus on input, call $nextTick, Wait until the page is rendered before executing the callback function this.$nextTick(function(){
this.$refs.inputTodo.focus() }) }, handleSaveTodo(todoObj, event){
// Cancel editing todoObj.isEdit = false if(!event.target.value.trim()) return alert(' Item content cannot be empty !') this.$bus.$emit('fnUpdateTodo', todoObj.id, event.target.value) } }, // introduce Body From the todoObj and App From the fnCheckTodo Method props: ['todoObj'], } </script>
<style scoped> nav{
background: rgb(196, 100, 100); padding: 20px; font-size: 1.1em; } button{
float:right; font-size: 1.1em; display: none; } input{
width:1.5em; height:1.5em } .input{
font-size:1.1em; width: 200px; } nav:hover{
background: rgb(31, 101, 167); } nav:hover button{
display: block; } .come{
animation: fromRight linear 1s; } .to{
animation: fromRight linear 1s reverse; } /* Vue Automatically assign name by edit and flag The entry and exit styles of */ .edit-enter-active{
animation: fromRight linear 1s; } .edit-leave-active{
animation: fromRight linear 1s reverse; } /* Vue Animation */ @keyframes fromRight{
from{
transform: translateX(100px); opacity: 0; } to{
transform: translateX(0px); opacity: 100; } } </style>
These two days through a TodoList The case for the to-do list is Vue2 The study of , Personal feeling Vue Development is very convenient , And the logical hierarchy is very clear , Not like before ,HTML and JS All mixed together , It looks chaotic , Now use Vue Divide different parts into different components , And each component has a corresponding HTML、JS and CSS, Very convenient .
版权声明:本文为[You]所创,转载请带上原文链接,感谢。 https://qdmana.com/2022/174/202206231738391716.html