Vue3小知识大杂烩—自我浅析

v-if 与 v-show 有什么区别

  • v-if切换会创建/删除元素,v-show切换只是元素的展示/隐藏(display: none)
  • v-if切换会创建/销毁组件,v-show切换在创建完组件后只会隐藏(display: none)
  • 对于多个元素的控制可以用<template>包裹

列表循环时key的作用?

  • v-for可基于数组渲染列表,也可基于对象渲染列表
  • 可以使用值的范围
  • 可在组件上循环渲染
  • v-for默认使用“就地更新”策略,数据项的顺序被改变,Vue将不会移动DOM元素来匹配数据项的顺序,而是就地更新每个元素。
  • 为能跟踪每个节点的身份,重用和重新排序现有元素,提升性能,需要使用key

父子组件如何传递数据?

通过props传递数据,我们应该在一个子组件内部改变 prop。

这里有两种常见的试图变更一个 prop 的情形:

这个 prop 用来传递一个初始值;这个子组件接下来希望将其作为一个本地的 prop 数据来使用。在这种情况下,最好定义一个本地的 data property 并将这个 prop 作为其初始值:

props: ['initialCounter'],
data() {
  return {
    counter: this.initialCounter
  }
}
 

这个 prop 以一种原始的值传入且需要进行转换。在这种情况下,最好使用这个 prop 的值来定义一个计算属性:

props: ['size'],
computed: {
  normalizedSize: function () {
    return this.size.trim().toLowerCase()
  }
}
 

单向数据流指的是什么?有什么好处?

什么是单向数据流?

很多框架都使⽤单向数据流,指的是⽗组件能直接传递数据给⼦组件,⼦组件不能随意修改⽗组件状态

为什么要单向?

单向数据流的⽬的是让数据的传递变得简单、可控、可追溯。假设都是⽤双向数据流,⽗组件维护⼀个状态,并且传递给所有的⼦组件。当其中⼀个⼦组件通过双向数据流直接修改⽗组件的这个状态时,其他⼦组件也会被修改。当这个结果产⽣时我们⽆法得知是拿个⼦组件修改了数据,在项⽬庞⼤时数据的管理和追溯变得更复杂。

如果要双向如何实现?

⼀般来说,⽗组件可⽤通过设置⼦组件的props直接传递数据给⼦组件。⼦组件想传递数据给⽗组件时,可以在内部emit⼀个⾃定义事件,⽗组件可在⼦组件上绑定该事件的监听,来处理⼦组件emit的事件和数据。

在Vue⾥,v-model实现的所谓双向绑定,本质上就这种⽅式。

v-text 和 v-html 有什么区别

v-text是直接插入文本

v-html是将它作为html片段插入的

    <div id="app">
      <fieldset>
        <legend>v-html&&v-text</legend>
        <div v-html="pushHTML"></div>
        <div v-text="pushHTML"></div>
      </fieldset>
    </div>
    <script>
      const App = {
        data() {
          return {
            visible: true,
            pushHTML: `<h1 style="color:red;">你好我的世界</h1>`,
          };
        },
      };

      Vue.createApp(App).mount('#app');
    </script>
 

image-20210512201002862

data 为什么要是函数

data() {
 return {
   	 ...
 }
}
 

data选项是一个函数,返回的是一个对象,相对于是一个给定初始值的地方,如果不给初始值,可以使用null或者undefined代替。

这里面的数据都是不响应式的,一般在实例挂载后就不会再次读取里面的数据。

计算属性缓存是什么

计算属性有级存机制,如果依赖的数据未发生改变,则不会重新计算而是直接使用缓存值

注意methods和computed里面的方法不要使用箭头函数,否则this就不是vm对象了

<div id="computed-basics" class="demo">
  <p>Has published books:</p>
  <span>{{ publishedBooksMessage }}</span>
</div>
<script>
Vue.createApp({
  data() {
    return {
      author: {
        name: 'John Doe',
        books: ['Vue 2 - Advanced Guide',
          'Vue 3 - Basic Guide',
          'Vue 4 - The Mystery']
      }
    }
  },
  computed: {
    // a computed getter
    publishedBooksMessage() {
      // `this` points to the vm instance
      return this.author.books.length > 0 ? 'Yes' : 'No'
    }
  }
}).mount('#computed-basics')
</script>
 

计算属性只在相关响应式依赖发生改变时它们才会重新求值。这就意味着只要 author.books 还没有发生改变,多次访问 publishedBookMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。

如果是方法的,他就会在每次调用时都会执行。

watch、计算属性有什么区别

用Watch的时候

  • 当只需要根据data中某个property的变化做出反应,但不一定需要结果时
  • 当有异步操作时
  • 当需要用旧值时

watch会监控data中某个property的变化,执行函数。

而计算属性是根据监控某个property变化得到的一个返回值。

在Vue中组件的全局注册和局部注册有什么区别,如何局部注册组件?

全局组件注册

const app = Vue.createApp({})

app.component('my-component-name', {
  // ... 选项 ...
})
 

局部组件的注册

注意注册的组件要在调用之前,先注册后调用。

const ComponentA = {
  /* ... */
}
const ComponentB = {
  /* ... */
}
const ComponentC = {
  /* ... */
}
const app = Vue.createApp({
  components: {
    'component-a': ComponentA,
    'component-b': ComponentB
  }
})

app.moun("#app")
 

两者的区别

  • 局部注册的组件在其子组件中不可用
  • 全局注册的组件可以在应用中的任何组件的模板中使用。

如何传递一个字符串类型的prop给子组件?数字类型呢?如何动态给prop赋值?

自定义传值的方式来解决上面的问题。。这时,你可以以对象形式列出 prop,这些 property 的名称和值分别是 prop 各自的名称和类型:

props: {
  title: String,
  likes: Number,
  isPublished: Boolean,
  commentIds: Array,
  author: Object,
  callback: Function,
  contactsPromise: Promise // 或任何其他构造函数
}
 

静态传值

<blog-post title="我的世界"></blog-post>
 

我们不仅可以静态的赋值,还可以动态的赋值

<!-- 动态赋予一个变量的值 -->
<blog-post v-bind:title="post.title"></blog-post>
// 下面是 v-bind的语法糖
<blog-post :title="post.title"></blog-post>

<!-- 动态赋予一个复杂表达式的值 -->
<blog-post :title="post.title + ' by ' + post.author.name"></blog-post>
 

同时还可以传入数字、布尔值、数组、对象,等等。

对于组件来说非prop的attribute怎么处理?

我们可以通过 $attrs来给需要的元素添加事件

<date-picker data-status="activated"></date-picker>

app.component('date-picker', {
  inheritAttrs: false,
  template: `
    <div class="date-picker">
      <input type="datetime" v-bind="$attrs" />
    </div>
  `
})
 

v-model:foo=”bar”与:foo=”bar”有什么区别?如何实现v-model:foo=”bar” ?

v-model:foo="bar"
// 等价于
:foo="bar" @updata:foo="bar=$event"
 

:foo="bar"相当于给子组件传递一个props,它的值是bar里面的内容

v-model:foo="bar"相当于在:foo="bar"上添加了事件响应

Vue中的插槽是什么?

插槽就是slot,说通俗一点就是占位置,当使用该组件标签时候,组件标签里面的内容就会自动填坑

例如下面代码

<div>
    <todo-button>
      Add todo
    </todo-button>
</div>

<!-- todo-button 组件模板 -->
<button class="btn-primary">
  <slot></slot>
</button>
 

上面的代码就会被翻译成

<button class="btn-primary">
 Add todo
</button>
 

如何实现多层级嵌套的父子组件数据传递?

使用Provide / Inject

父组件有一个 provide 选项来提供数据,子组件有一个 inject 选项来开始使用这些数据。

传递大范围的data和method共用。

<div id="app">
  <div :class="`app theme-${themeName} fontSize-${fontSizeName}` ">
    <Child></Child>
  </div>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
  //  孙子组件
  const ChangeThemeButton = {
    inject: ["changeTheme", "changeFontSize"],
    template: `
          <div>
            <button @click="changeTheme">换肤</button>
            <button @click="changeFontSize('big')">大</button>
            <button @click="changeFontSize('small')">小</button>
            <button @click="changeFontSize('normal')">正常</button>
          </div>
          `,
  };
  // 子组件
  const Child = {
    components: {
      ChangeThemeButton,
    },

    template: `
        <div>
        你好
        <ChangeThemeButton/>
        </div>
    `,
  };

  //  父组件
  Vue.createApp({
    components: {
      Child,
    },
    data() {
      return {
        themeName: "blue",
        fontSizeName: "normal",
      };
    },
    provide() {
      return {
        changeTheme: this.changeTheme,
        changeFontSize: this.changeFontSize,
      };
    },
    methods: {
      changeTheme() {
        if (this.themeName === "blue") {
          this.themeName = "red";
        } else {
          this.themeName = "blue";
        }
      },
      changeFontSize(name) {
        if (["big", "small", "normal"].indexOf(name) >= 0) {
          this.fontSizeName = name;
        }
      },
    },
  }).mount("#app");
</script>

<style>
  .app {
    font-family: "Avenir", Helvetica, Arial, sans-serif;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-align: center;
    color: #2c3e50;
    margin-top: 60px;
  }
  .app.theme-blue button {
    background: blue;
    color: white;
  }
  .app.theme-blue {
    color: darkblue;
  }

  .app.theme-red button {
    background: red;
    color: white;
  }
  .app.theme-red {
    color: darkred;
  }
  .app button {
    font-size: inherit;
  }
  .app.fontSize-small {
    font-size: 12px;
  }
  .app.fontSize-big {
    font-size: 20px;
  }
</style>
 

keep-alive有什么作用

保持组件的状态,以避免反复渲染导致的性能问题。

执行下面的代码,在input标签里面输入东西,跳转到其他组件 在跳转回来,你会发现,之前输入的东西是没有改变的,并不会清除。

<div id="app">
  <button v-for="tab in tabs" :key="tab" @click="currentTab = tab">{{tab}}</button>
  <keep-alive>
    <component :is="currentTabComponent" class="tab"></component>
  </keep-alive>
</div>

<script src="https://unpkg.com/vue@next"></script>
<script>
  const app = Vue.createApp({
    data() {
      return {
        currentTab: "Home",
        tabs: ["Home", "Input"],
      };
    },
    computed: {
      currentTabComponent() {
        return "tab-" + this.currentTab.toLowerCase();
      },
    },
  });

  app.component("tab-home", {
    template: `<div>Home component</div>`,
  });
  app.component("tab-input", {
    template: `<div><input type="text"/></div>`,
  });

  app.mount("#app");
</script>
 

动态组件是什么?

在不同组件之间进行动态切换,上面的一问中就是动态组件。

<!-- 组件会在 `currentTabComponent` 改变时改变 -->
<component :is="currentTabComponent"></component>
 

Vue里有哪些方法实现过渡或者动画效果

使用class实现动画

也就是先写好CSS3的动画样式,然后再需要的标签上添加class形成动画

<div id="app">
  <div :class="['box', {active: isActive}]">box</div>
  <button @click="isActive = !isActive">Click me</button>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
  Vue.createApp({
    data() {
      return {
        isActive: false
      }
    }
  }).mount('#app')
</script>

<style>
  .box {
    width: 300px;
    height: 200px;
    box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.2);
    transition: all 0.3s ease;
  }
  .active {
    transform: translateX(100px);
  }
</style>
 

使用style动画过渡

和class类似,将样式卸载标签上,适合添加的样式较少的情况下使用。

<div id="app">
  <div class="box" :style="{backgroundColor:`rgb(${R},${G},${B})`}"></div>
  <input type="range" min="0" max="255" v-model="R" />
  R:{{R}}<br>
  <input type="range" min="0" max="255" v-model="G" />
  G:{{G}}<br>
  <input type="range" min="0" max="255" v-model="B" />
  B:{{B}}<br>
</div>
<script src="https://unpkg.com/vue@next"></script>

<script>
  Vue.createApp({
    data() {
      return {
        R:0,
        G:0,
        B:0
      };
    },
  }).mount("#app");
</script>

<style>
  .box{
    width: 200px;
    height: 200px;
  }
</style>
 

使用transition来制作动画过渡

将需要制作动画的标签放入 transition里面。然后使用 name属性制作动画。

对于这些在过渡中切换的类名来说,如果你使用一个没有名字的 <transition>,则 v- 是这些class名的默认前缀。如果你使用了 <transition name="fade">,那么 v-enter-from会替换为 fade-enter-from

我们可以用 <transition> 组件上的 duration来定制一个显性的过渡持续时间 (以毫秒计):

<div id="demo">
  <button @click="show = !show">Toggle</button>

  <transition name="fade">
    <p v-if="show">hello</p>
  </transition>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
  const Demo = {
    data() {
      return {
        show: true,
      };
    },
  };

  Vue.createApp(Demo).mount("#demo");
</script>
<style>
  .fade-enter-active,
  .fade-leave-active {
    transition: opacity 0.5s ease;
  }

  .fade-enter-from,
  .fade-leave-to {
    opacity: 0;
  }
</style>
 

多个元素过渡

同时生效的进入和离开的过渡不能满足所有要求,所以 Vue 提供了过渡模式

  • in-out: 新元素先进行过渡,完成之后当前元素过渡离开。
  • out-in: 当前元素先进行过渡,完成之后新元素过渡进入。
<div id="app">
  <button v-for="tab in tabs" :key="tab" :class="{ active: currentTab === tab }" @click="currentTab = tab">
    {{ tab }}
  </button>
  <transition mode="out-in" name="fade">
    <keep-alive>
      <component :is="currentTab" class="tab"></component>
    </keep-alive>
  </transition>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
  const app = Vue.createApp({
    data() {
      return {
        currentTab: 'Tab1',
        tabs: ['Tab1', 'Tab2']
      }
    },
  })
  app.component('Tab1', {
    template: `<div>Tab1 content</div>`,
  })
  app.component('Tab2', {
    template: `<div>
      <input v-model="value" /> {{value}}
    </div>`,
    data() { return { value: 'hello' } },
  })
  app.mount('#app')
</script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.0/animate.min.css" rel="stylesheet" />

<style>
  .active {
    background: #ccc;
  }

  .fade-enter-active,
  .fade-leave-active {
    transition: all .3s;
  }

  .fade-enter-from,
  .fade-leave-to {
    opacity: 0;
  }

</style>
 

多个组件的过渡

<div id="app">
  <button
    v-for="tab in tabs"
    :key="tab"
    :class="{active:currentTab === tab}"
    @click="currentTab = tab"
  >
    {{tab}}
  </button>
  <transition
    mode="out-in"
    enter-active-class="animate__animated animate__fadeInLeft"
    leave-active-class="animate__animated animate__fadeOutRight"
  >
    <keep-alive>
      <component :is="currentTab" class="tab"></component>
    </keep-alive>
  </transition>
</div>

<script src="https://unpkg.com/vue@next"></script>
<script>
  const app = Vue.createApp({
    data() {
      return {
        currentTab: "Tab1",
        tabs: ["Tab1", "Tab2"],
      };
    },
  });
  app.component("Tab1", {
    template: `<div>Tab1 content</div>`,
  });
  app.component("Tab2", {
    template: `<div>
                <input v-model="value" /> 
                .{{value}}
              </div>`,
    data() {
      return { value: "hello" };
    },
  });
  app.mount("#app");
</script>
<link
  href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.0/animate.min.css"
  rel="stylesheet"
/>

<style>
  :root {
    --animate-duration: 0.3s;
    --animate-delay: 0;
  }
  .active {
    background-color: #ccc;
  }
</style>

 

transition组件实现过渡效果怎么使用

  • v-enter-from:在元素被插入之前生效,在元素被插入之后的下一帧移除
  • v-enter-active:定义进入过渡生效时的状态
  • v-enter-to:定义进入过渡的结束状态。在元素被插入之后下一帧生效,在过渡/动画完成之后移除
  • v-leave-from:在离开过渡被触发时立刻生效,下一帧被移除
  • v-leave-active:定义离开过渡生效时的状态
  • v-leave-to:离开过渡的结束状态。在离开过渡被触发之后下一-帧生效,在过渡/动画完成之后移除

列表过渡怎么做

在需要过渡的列表外面添加 transition-group,记住必加一个 tag让他成为一个便签包裹在列表过渡外面。

 <transition-group name="list" tag="div">
    <div v-for="(value, index) in news" :key="value">
      {{value}} 
      <button @click="news.splice(index, 1)">删除</button>
    </div>
  </transition-group>
 

什么是组合式 API

当我们在面临大型应用是,共享和重用代码变得尤为重要。

我们将这些重用的放在 setup

注意:由于在执行 setup 时,组件实例尚未被创建,因此在 setup 选项中没有 this。这意味着,除了 props 之外,你将无法访问组件中声明的任何属性——本地状态计算属性方法

原创文章,作者:我心飞翔,如若转载,请注明出处:https://www.pipipi.net/14650.html

发表评论

登录后才能评论