1 Star 0 Fork 0

falcon / vue-firebase-study

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
README.md 39.03 KB
一键复制 编辑 原始数据 按行查看 历史
falcon 提交于 2021-01-11 16:18 . update day17

#学习Vue 和 Firebase

🛠️ 资源

Vue.js 官网中文文档 (v2) Vue-cli github Vue-cli (Vue.js 开发的标准工具)

Day 1

  • Vue.js的引入
  • 数据绑定
  • 在模板使用函数
  • 在模板中绑定属性v-bind ,可以使用 : 简写
  • 在模板中绑定事件 v-on ,使用@简写,如 @click="methodName"
  • 使用 v-model (未深入)
  • 使用 修饰器 键盘/事件 修饰器,(未深入)
  • 模板基本语法,条件,循环(未深入)

Day 2

因为版本更新,这块跟视频的差别很大,当前使用 版本 vue --version

@vue/cli 4.3.1

  • vue-cli 安装:

    npm install -g @vue/cli

    快速原型开发 vue serve ,默认入口可以是 main.js、index.js、App.vue 或 app.vue 中的一个

  • 创建一个项目

    vue create yourProject

    运行

    cd yourProjectPath
    npm run serve
    # 相当于
    node_modules/.bin/vue-cli-service serve

    查错

    npm run lint

    以上命令注册在项目的 package.jsonscripts项中
    创建项目时可以设定配置,加入相应的组件

  • 保存预设配置

  • 安装plugins 如安装 vue-plugin-vuetify 对应到 package.jsondevDependencies项目

    vue add vuetify       

Day3

  • 构建web component

    用法

    vue build  -h 
    -t, --target <target>  Build target (app | lib | wc | wc-async, default: app)
    -n, --name <name>      name for lib or web-component mode (default: entry filename)
    -d, --dest <dir>       output directory (default: dist)
    -h, --help             output usage information

    如将online.vue构建为online-statusweb component

    vue build online.vue --target wc --name online-status    
  • 使用 web component 如使用之前构建的 online-status

    <meta charset="utf-8">
    <title>online-status demo</title>
    <script src="https://unpkg.com/vue"></script>
    <script src="./online-status.js"></script>
    ...
    <online-status status="online"></online-status>
    ...
    
  • vue ui 图形化工具 vue-cli 的 web图形化 界面

day4 -> day5

- ES6
- async 

- promise 

- await

day6

2020.07.24

  • 不必记住vue的npm run命令,因为项目的package.json文件可以找到这些命令
 "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint"
  }
  • 运行开发服务器时出错 npm run serve
> vue-tobe@0.1.0 serve /Users/falcon/projects/js/vue-firebase/day6/vue-tube
> vue-cli-service serve

 INFO  Starting development server...
 ERROR  Error: No valid exports main found for '/Users/falcon/projects/js/vue-firebase/day6/vue-tube/node_modules/colorette'
Error: No valid exports main found for '/Users/falcon/projects/js/vue-firebase/day6/vue-tube/node_modules/colorette'

解决方法有两个:

1. `npm i colorette@1.2.0`  # 必须带版本号才管用 

2. 升级 `node.js` 
    `homebrew`安装的 `node.js` 有时并不是最新的版本,就算使用homebrew升级也升不到官方最新版本。`N`是node内置的版本管理器,使用`npm install -g n`安装,然后执行 `sudo n latest` 可升到最新版本。

day 7

2020.07.30

安装nvm ,node版本管理工具。 项目用法和文档

brew install nvm

常用的指令

  • 查看版本
nvm ls-remote #远程所有node版本
nvm ls #本地所有安装的node版本
  • 安装
nvm install 版本 #如果版本写node,会安装最新版本的node并自动切换,如果填写lts,会安装lts版本,如果填写具体版本号,会安装指定版本
  • 设置默认版本
nvm alias default node #使用最新版本
nvm alias default 'lts/*' #使用 `lts/*` 版本
nvm alias default 12.18.3 #使用 `12.18.3`版本
  • 切换当前使用的node版本
nvm use #会使用~/.nvmrc 指定的 node 版本
nvm use 12.18.3  #使用12.18.3版本
nvm use node/stable/unstable #切换最新版本/稳定版本/lts
  • 删除node版本
nvm uninstall 8 #删除8.x版本
nvm uninstall unstable #删除unstable版本

ps: 使用nvm管理node版本后,全局安装模块时不需要用sudo

day8

2020.08.08

vue文档学习

  • Vue 实例还暴露了一些有用的实例属性与方法。 它们都有前缀 $ 如:
var vm = new Vue(
    el:'#app',
    data:{
        name:"falcon"
    }
)
console.log('实例属性')
console.log(vm.$el)
console.log(vm.$data)
console.log (vm.$el === document.getElementById('app')) // => true


// 这个回调将在 `vm.wage` 改变后调用

vm.$watch('wage', function(newVal, oldVal) {
  console.log(this, `wage change from ${oldVal} to ${newVal}`)
  }
);
  • 不要在生命周期或实例方法里使用箭头函数,

如:

created: () => console.log(this.a)
vm.$watch('wage', (newVal, oldVal) => console.log(this,`wage change from ${oldVal} to ${newVal}`)) //这个this会向上查找不是vue实例,而是window

因为箭头函数并没有 thisthis 会作为变量一直向上级词法作用域查找,直至找到为止,经常导致 Uncaught TypeError: Cannot read property of undefinedUncaught TypeError: this.myMethod is not a function 之类的错误

不改变值

<span v-once>这个值不会改变:  wage: {{wage}}</span>

输出原始html

<span v-html="rawHtml"></span>

动态绑定属性/事件

好像这个动态绑定的属性和事件名不能用驼峰写法?会自动转化成小写的data属性

<a v-bind:[attr]="url"> 动态绑定属性 </a>
<a v-on:[eventname]="doSomething"> 动态绑定事件 </a>
  • 计算属性
computed: { //计算属性

    reversedName: function () {
      return this.name.split('').reverse().join('')  
    }

  },

计算属性是基于它们的响应式依赖进行 缓存 的,只有相关的响应式依赖发生变化时才会重新计算。 相比之下,每当触发重新渲染时,调用方法将总会再次执行函数。

  • 侦听属性
  watch: {
    firstName: function (val) {
      this.fullName = val + ' ' + this.lastName
    },
    lastName: function (val) {
      this.fullName = this.firstName + ' ' + val
    }
  }

尽量使用计算属性而不是命令式的 watch 回调

  • 计算属性的 setter

运行 vm.label2 = "test" 时,setter 会被调用

computed:{
    label2: {

        get() { //getter
        return this.name + this.age + '@' + Date.now()
        },
        set() { //setter
        console.log('Changed @' + Date.now())
        this.name += ' hack';
        
        }
    }
}
  • 侦听器
watch: {
    ...
}

vue项目的bin目录位于 node_modules/.bin/ 运行npm run serve 相当于 node_modules/.bin/vue-cli-service serve

vue.js为什么在component的template的root标签中不能使用v-for?

如果后续安装 vue-router插件,App.vue 会被覆盖

  • 使用 Netlify 免费部署

参考视频: Deploy Websites In Seconds With Netlify

部署了github page:https://amazing-goldstine-c1bf0b.netlify.app/

day9

2020.08.10

  • 向组件中增加class 当在一个自定义组件上使用 class property 时,这些 class 将被添加到该组件的根元素上面。这个元素上已经存在的 class 不会被覆盖。 如:

组件Header.vue:


<template>
  <h1 class="header">header</h1>
  ...
</template>

引入Header的组件

import Header from '../components/Header.vue'

<template>
<div id="app">
  <Header class="custom-header">
  ...
</div>
</tempate>

最后会被渲染为:

<h1 class="header custom-header">header</h1>
  • 绑定内联样式 v-bind:style 的对象语法十分直观——看着非常像 CSS,但其实是一个 JavaScript 对象。CSS property 名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用引号括起来) 来命名
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
data: {
  activeColor: 'red',
  fontSize: 30
}
  • 用 key 管理可复用的元素
<template v-if="loginType === 'username'">
  <label>Username</label>
  <input placeholder="Enter your username" key="username-input">
</template>
<template v-else>
  <label>Email</label>
  <input placeholder="Enter your email address" key="email-input">
</template>

如果不设置key时,loginType 变化时,input 内的输入值会保留,仅placeholer会被替换

  • 不推荐同时使用 v-if 和 v-for

当 v-if 与 v-for 一起使用时,v-for 具有比 v-if 更高的优先级。

  • v-for 列表渲染

语法:

  <li v-for="item in items" :key="item.message">
    {{ item.message }}
  </li>

支持第二个参数:索引

  <li v-for="(item, index) in items">
    {{ parentMessage }} - {{ index }} - {{ item.message }}
  </li>
  • v-for 对象渲染

语法:

  <li v-for="value in object">
    {{ value }}
  </li>

第二个参数name表示对象属性名

 <div v-for="(value, name) in object">
  {{ name }}: {{ value }}
 </div>

第三个参数index表示索引

<div v-for="(value, name, index) in object">
  {{ index }}. {{ name }}: {{ value }}
</div>
  • 在计算属性不适用的情况下 (例如,在嵌套 v-for 循环中) 你可以使用一个方法:
<ul v-for="set in sets">
  <li v-for="n in even(set)">{{ n }}</li>
</ul>
data: {
  sets: [[ 1, 2, 3, 4, 5 ], [6, 7, 8, 9, 10]]
},
methods: {
  even: function (numbers) {
    return numbers.filter(function (number) {
      return number % 2 === 0
    })
  }
}
  • 2.2.0+ 的版本里,当在组件上使用 v-for 时,key 现在是必须的。
<my-component
  v-for="(item, index) in items"
  v-bind:item="item"
  v-bind:index="index"
  v-bind:key="item.id"
></my-component>
  • 这里的 is="todo-item" attribute。这种做法在使用 DOM 模板时是十分必要的,因为在
      元素内只有
    • 元素会被看作有效内容。这样做实现的效果与 相同,但是可以避开一些潜在的浏览器解析错误。
     <li
          is="todo-item"
          v-for="(todo, index) in todos"
          v-bind:key="todo.id"
          v-bind:title="todo.title"
          v-on:remove="todos.splice(index, 1)"
        ></li>
    • 在内联语句处理器中访问原始的 DOM 事件。

      可以用特殊变量 $event 把它传入方法:

      <button v-on:click="warn('Form cannot be submitted yet.', $event)">
      Submit
      </button>
    • 访问原生事件对象

    methods: {
      warn: function (message, event) {
        // 现在我们可以访问原生事件对象
        if (event) {
          event.preventDefault()
        }
        alert(message)
        }
    }
    • 事件修饰符
     <!-- 阻止单击事件继续传播 -->
     <a v-on:click.stop="doThis"></a>
    
     <!-- 提交事件不再重载页面 -->
     <form v-on:submit.prevent="onSubmit"></form>
    
     <!-- 修饰符可以串联 -->
     <a v-on:click.stop.prevent="doThat"></a>
    
     <!-- 只有修饰符 -->
     <form v-on:submit.prevent></form>
    
     <!-- 添加事件监听器时使用事件捕获模式 -->
     <!-- 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 -->
     <div v-on:click.capture="doThis">...</div>
    
     <!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
     <!-- 即事件不是从内部元素触发的 -->
     <div v-on:click.self="doThat">...</div>
     <!-- 点击事件将只会触发一次 -->
     <a v-on:click.once="doThis"></a>

    使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用 v-on:click.prevent.self 会阻止所有的点击,而 v-on:click.self.prevent 只会阻止对元素自身的点击。

    • 按键修饰符
    <!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` -->
    <input v-on:keyup.enter="submit">

    任意有效按键名转换为 kebab-case 来作为修饰符。如: page-down

     <input v-on:keyup.page-down="onPageDown">
    • 系统修饰键

    在 Mac 系统键盘上,meta 对应 command 键 (⌘)。在 Windows 系统键盘 meta 对应 Windows 徽标键 (⊞)。

    <!-- Alt + C -->
    <input v-on:keyup.alt.67="clear">
    
    <!-- Ctrl + Click -->
    <div v-on:click.ctrl="doSomething">Do something</div>
    • v-model 指令在表单、<textarea> 及 元素上创建双向数据绑定。

    v-model 在内部为不同的输入元素使用不同的 property 并抛出不同的事件:

    • text 和 textarea 元素使用 value property 和 input 事件;
    • checkbox 和 radio 使用 checked property 和 change 事件;
    • select 字段将 value 作为 property 并将 change 作为事件。
    • 在文本区域插值 (<textarea>{{text}}</textarea>) 并不会生效,应用 v-model 来代替。
     <textarea v-model="message" placeholder="add multiple lines"></textarea>
    • 多个复选框,绑定到同一个数组:
    <input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
    <label for="jack">Jack</label>
    <input type="checkbox" id="john" value="John" v-model="checkedNames">
    <label for="john">John</label>
    <input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
    <label for="mike">Mike</label>
    <br>
    <span>Checked names: {{ checkedNames }}</span>
    new Vue({
      el: '...',
      data: {
        checkedNames: []
      }
    })

    day10

    2020.08.11

    checkName是一个数组 ,值为input里的value
    
    - 如果 v-model 表达式的初始值未能匹配任何选项,<select> 元素将被渲染为“未选中”状态。在 iOS 中,这会使用户无法选择第一个选项。因为这样的情况下,iOS 不会触发 change 事件。因此,更推荐像下面这样提供一个值为空的禁用选项。
    
    ```html
    <div id="example-6">
      <select v-model="selected" multiple style="width: 50px;">
        <option>A</option>
        <option>B</option>
        <option>C</option>
      </select>
      <br>
      <span>Selected: {{ selected }}</span>
    </div>
    • option 用 v-for 渲染的动态选项:
    <select v-model="selected">
      <option v-for="option in options" v-bind:value="option.value">
        {{ option.text }}
      </option>
    </select>
    <span>Selected: {{ selected }}</span>
    new Vue({
      el: '...',
      data: {
        selected: 'A',
        options: [
          { text: 'One', value: 'A' },
          { text: 'Two', value: 'B' },
          { text: 'Three', value: 'C' }
        ]
      }
    })
    • 使用动态 property

    有时我们可能想把值绑定到 Vue 实例的一个动态 property 上,这时可以用 v-bind 实现,并且这个 property 的值可以不是字符串。

    • 单选按钮
    <input type="radio" v-model="pick" v-bind:value="a">

    选中时 vm.pick == vm.a

    • 复选框
    <input
      type="checkbox"
      v-model="toggle"
      true-value="yes"
      false-value="no"
    >
    

    这里的 true-value 和 false-value attribute 并不会影响输入控件的 value attribute,因为浏览器在提交表单时并不会包含未被选中的复选框。如果要确保表单中这两个值中的一个能够被提交,(即“yes”或“no”),请换用单选按钮。

    • 选择框的选项
    <select v-model="selected">
      <!-- 内联对象字面量 -->
      <option v-bind:value="{ number: 123 }">123</option>
    </select>
      // 当选中时
    typeof vm.selected // => 'object'
    vm.selected.number // => 123
    • 修饰符

      • lazy
      <!-- 在“change”时而非“input”时更新 -->
      <input v-model.lazy="msg">
      • number
      <!--自动将用户的输入值转为数值类型,可以给 v-model 添加 number 修饰符:-->
      <input v-model.number="age" type="number">
      • trim
      <!--自动过滤用户输入的首尾空白字符-->
      <input v-model.trim="msg">
    • 在组件上使用 v-model

    创建一个custom-input组件,注意其中的

    Vue.component('custom-input', {
      props: ['value'],
      template: `
        <input
          v-bind:value="value"
          v-on:input="$emit('input', $event.target.value)"
        >
      `
    })

    现在 v-model 就应该可以在这个组件上完美地工作起来了:

    <custom-input v-model="searchText"></custom-input>
    • 通过插槽分发内容

    创建一个自定义一个插槽组件,注意 <slot>元素

    Vue.component('alert-box', {
      template: `
        <div class="demo-alert-box">
          <strong>Error!</strong>
          <slot></slot>
        </div>
      `
    })

    用法:

    <alert-box>
      Something bad happened.
    </alert-box>

    处会被插入的文字替换

    • 动态组件 (@todo)
    <!-- 组件会在 `currentTabComponent` 改变时改变 -->
    <component v-bind:is="currentTabComponent"></component>

    参考代码:https://hi.cellmean.com/p/a11cde485cc1

    • 解析dom模板时特殊元素和限制

    有些 HTML 元素,诸如 <ul><ol><table><select>,对于哪些元素可以出现在其内部是有严格限制的。而有些元素,诸如 <li><tr><option>,只能出现在其它某些特定的元素内部。

    不能这样写,因为要能出现在 table 元素下的元素有限制

    <table>
      <blog-post-row></blog-post-row>
    </table>

    可以使用 is 替换

    <table>
      <tr is="blog-post-row"></tr>
    </table>

    需要注意的是如果我们从以下来源使用模板的话,这条限制是不存在的:

    • 字符串 (例如:template: '...')

    • 单文件组件 (.vue)

    • <script type="text/x-template">

    • 组件名大小写

    支持 kebab-case 和 PascalCase命名方式

    注意:直接在 DOM (即非字符串的模板) 中使用时只有 kebab-case 是有效的。

    • 组件注册

      • 全局注册,在任何新创建的 Vue 根实例 (new Vue) 及子组件中都可以使用
      Vue.component('my-component-name', {
      // ... 选项 ...
      })
      • 局部注册
      var ComponentA = { /* ... */ }

      实例或子组件使用时需要添加 components 属性

      new Vue({
        el: '#app',
        components: {
          'component-a': ComponentA,
          'component-b': ComponentB
        }
      })
      • 模块系统中局部注册
      import ComponentA from './ComponentA'
      import ComponentC from './ComponentC'
      
      export default {
        components: {
          ComponentA,
          ComponentC
        },
        // ...
      }
      • 基础组件的自动化全局注册 (@todo)

      需要 webpack (或在内部使用了 webpack 的 Vue CLI 3+) 支持

    • Prop 的大小写 (camelCase vs kebab-case)

    如果在prop中使用 camelCase

    Vue.component('blog-post', {
      // 在 JavaScript 中是 camelCase 的
      props: ['postTitle'],
      template: '<h3>{{ postTitle }}</h3>'
    })

    在HTML中必须改成kebab-case ,

    <!-- 在 HTML 中是 kebab-case 的 -->
    <blog-post post-title="hello!"></blog-post>

    如果你使用字符串模板,那么这个限制就不存在了。

    • prop类型

    可以使用对象形式的写法指定名称和类型

      props: {
        title: String,
        likes: Number,
        isPublished: Boolean,
        commentIds: Array,
        author: Object,
        callback: Function,
        contactsPromise: Promise // or any other constructor
      }
    • 传递静态或动态 Prop

    静态:

    作为字符串传入

    <blog-post title="My journey with Vue"></blog-post>

    注意:这里的Prop posTitle,在html页使用时会转成 post-title, 除非在 字符串模板 使用才没有这种限制。

    
    Vue.component('blog-post', {
      // 在 JavaScript 中是 camelCase 的
      props: ['postTitle'],
      template: '<h3>{{ postTitle }}</h3>'
    })
    <blog-post post-title="hello!"></blog-post>

    Vue的字符串模板指的是在Vue实例中的template属性所对应的字符串

    动态:

    
    <!-- 动态赋予一个变量的值 -->
    <blog-post v-bind:title="post.title"></blog-post>
    
    <!-- 动态赋予一个复杂表达式的值 -->
    <blog-post
      v-bind:title="post.title + ' by ' + post.author.name"
    ></blog-post>
    • 传入一个数字
     <!-- 即便 `42` 是静态的,我们仍然需要 `v-bind` 来告诉 Vue -->
     <!-- 这是一个 JavaScript 表达式而不是一个字符串。-->
     <blog-post v-bind:likes="42"></blog-post>
    • 传入一个布尔值
    <!-- 包含该 prop 没有值的情况在内,都意味着 `true`。-->
    <blog-post is-published></blog-post>
    
    <!-- 即便 `false` 是静态的,我们仍然需要 `v-bind` 来告诉 Vue -->
    <!-- 这是一个 JavaScript 表达式而不是一个字符串。-->
    <blog-post v-bind:is-published="false"></blog-post>
    
    <!-- 用一个变量进行动态赋值。-->
    <blog-post v-bind:is-published="post.isPublished"></blog-post>
    • 传入一个对象的 所有 property

    可以使用不带参数的 v-bind (取代 v-bind:prop-name)。例如,对于一个给定的对象 post:

    <blog-post v-bind="post"></blog-post>

    等价于

    <blog-post
      v-bind:id="post.id"
      v-bind:title="post.title"
    ></blog-post>
    • 单向数据流

    所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解。

    额外的,每次父级组件发生变更时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。

    注意在 JavaScript 中对象和数组是通过引用传入的,所以对于一个数组或对象类型的 prop 来说,在子组件中改变变更这个对象或数组本身将会影响到父组件的状态。

    • Prop 验证

    为了定制 prop 的验证方式,你可以为 props 中的值提供一个带有验证需求的对象,而不是一个字符串数组。例如:

    Vue.component('my-component', {
      props: {
        // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
        propA: Number,
        // 多个可能的类型
        propB: [String, Number],
        // 必填的字符串
        propC: {
          type: String,
          required: true
        },
        // 带有默认值的数字
        propD: {
          type: Number,
          default: 100
        },
        // 带有默认值的对象
        propE: {
          type: Object,
          // 对象或数组默认值必须从一个工厂函数获取
          default: function () {
            return { message: 'hello' }
          }
        },
        // 自定义验证函数
        propF: {
          validator: function (value) {
            // 这个值必须匹配下列字符串中的一个
            return ['success', 'warning', 'danger'].indexOf(value) !== -1
          }
        }
      }
    })

    注意那些 prop 会在一个组件实例创建之前进行验证,所以实例的 property (如 data、computed 等) 在 default 或 validator 函数中是不可用的。

    当验证失败时,(开发环境构建版本的) Vue 将会产生一个控制台的警告。

    • 非 Prop 的 Attribute

    如父级这样调用组件:

    <bootstrap-date-input data-date-picker="activated"></bootstrap-date-input>

    这里的 data-date-picker属性不是一个prop,而是attribute时,这样写之后这个属性会添加到组件的根元素上。

    • 替换/合并已有的 Attribute

    对于绝大多数 attribute 来说,从外部提供给组件的值会替换掉组件内部设置好的值。所以如果传入 type="text" 就会替换掉 type="date" 并把它破坏!庆幸的是,class 和 style attribute 会稍微智能一些,即两边的值会被合并起来,从而得到最终的值:

    • 禁用 Attribute 继承

    如果你不希望组件的根元素继承 attribute,你可以在组件的选项中设置 inheritAttrs: false

    注意 inheritAttrs: false 选项不会影响 style 和 class 的绑定。

    • $attrs property 与 inheritAttrs

    该 property 包含了传递给一个组件的 attribute 名和 attribute 值,例如:

    {
      required: true,
      placeholder: 'Enter your username'
    }

    配合 inheritAttrs: false 使用

    Vue.component('base-input', {
      inheritAttrs: false,
      props: ['label', 'value'],
      template: `
        <label>
          {{ label }}
          <input
            v-bind="$attrs"
            v-bind:value="value"
            v-on:input="$emit('input', $event.target.value)"
          >
        </label>
      `
    })

    调用 :

    <base-input
      v-model="username"
      required
      placeholder="Enter your username"
    ></base-input>

    这个模式允许你在使用基础组件的时候更像是使用原始的 HTML 元素,而不会担心哪个元素是真正的根元素:

    Day 11

    2020.08.15

    • 自定义组件的 v-model
    Vue.component('base-checkbox', {
      model: {
        prop: 'checked',
        event: 'change'
      },
      props: {
        checked: Boolean
      },
      template: `
        <input
          type="checkbox"
          v-bind:checked="checked"
          v-on:change="$emit('change', $event.target.checked)"
        >
      `
    })

    用法:

    <base-checkbox v-model="lovingVue"></base-checkbox>
    • 将原生事件绑定到组件 你可能有很多次想要在一个组件的根元素上直接监听一个原生事件。这时,你可以使用 v-on 的 .native 修饰符
    <base-input v-on:focus.native="onFocus"></base-input>

    vue 提供了一个 $listeners property,它是一个对象,里面包含了作用在这个组件上的所有监听器。例如:

    {
      focus: function (event) { /* ... */ }
      input: function (value) { /* ... */ },
    }

    有了这个 $listeners property,你就可以配合 v-on="$listeners" 将所有的事件监听器指向这个组件的某个特定的子元素。

    • .sync 修饰符

    我们推荐以 update:myPropName 的模式触发事件

    子组件触发事件 :

    this.$emit('update:title', newTitle)

    父组件监听事件并触发更新

    <text-document
      v-bind:title="doc.title"
      v-on:update:title="doc.title = $event"
    ></text-document>

    这种模式可以简写成

    <text-document v-bind:title.sync="doc.title"></text-document>

    将 v-bind.sync 用在一个字面量的对象上,例如 v-bind.sync=”{ title: doc.title }”,是无法正常工作的,因为在解析一个像这样的复杂表达式的时候,有很多边缘情况需要考虑

    下面这样会把 doc 对象中的每一个 property (如 title) 都作为一个独立的 prop 传进去,然后各自添加用于更新的 v-on 监听器。

    <text-document v-bind.sync="doc"></text-document>

    将 v-bind.sync 用在一个字面量的对象上,例如 v-bind.sync=”{ title: doc.title }”,是无法正常工作的,因为在解析一个像这样的复杂表达式的时候,有很多边缘情况需要考虑

    • 插槽编译作用域
    <navigation-link url="/profile">
      Clicking here will send you to: {{ url }}  
    </navigation-link>

    如果url是插槽内部 <navigation-link> 的属性变量,外面是访问不到的,这里会显示 undefined

    • 插槽后备内容

    如在一个 submit-button的组件中

    <button type="submit">
      <slot>Submit</slot>
    </button>

    调用时不带内容

    <submit-button></submit-button>

    渲染结果:

    <button type="submit">
      Submit
    </button>
    • 具名插槽

    <slot> 元素有一个特殊的 attribute:name。这个 attribute 可以用来定义额外的插槽:

    <div class="container">
      <header>
        <slot name="header"></slot>
      </header>
      <main>
        <slot></slot>
      </main>
      <footer>
        <slot name="footer"></slot>
      </footer>
    </div>

    一个不带 name 的 <slot> 出口会带有隐含的名字 “default”。

    在向具名插槽提供内容的时候,我们可以在一个 <template> 元素上使用 v-slot 指令,并以 v-slot 的参数的形式提供其名称

    <base-layout>
      <template v-slot:header>
        <h1>Here might be a page title</h1>
      </template>
    
      <p>A paragraph for the main content.</p>
      <p>And another one.</p>
    
      <template v-slot:footer>
        <p>Here's some contact info</p>
      </template>
    </base-layout>

    最终渲染为:

    <div class="container">
      <header>
        <h1>Here might be a page title</h1>
      </header>
      <main>
        <p>A paragraph for the main content.</p>
        <p>And another one.</p>
      </main>
      <footer>
        <p>Here's some contact info</p>
      </footer>
    </div>

    注意 v-slot 只能添加在 <template>

    在动态组件上使用 keep-alive

    动态切换组件时 如:

    <component v-bind:is="currentTabComponent"></component>

    重新切换到原来的组件,会重新创建组件,原来组件的状态会丢失,可以使用 <keep-alive>标签缓存原来组件

    <!-- 失活的组件将会被缓存!-->
    <keep-alive>
      <component v-bind:is="currentTabComponent"></component>
    </keep-alive>

    演示代码(多标签切换恢复时保持原组件状态)

    • 异步组件

    Vue 允许你以一个工厂函数的方式定义你的组件,这个工厂函数会异步解析你的组件定义。Vue 只有在这个组件需要被渲染的时候才会触发该工厂函数,且会把结果缓存起来供未来重渲染。例如:

    Vue.component('async-example', function (resolve, reject) {
      setTimeout(function () {
        // 向 `resolve` 回调传递组件定义
        resolve({
          template: '<div>I am async!</div>'
        })
      }, 1000)
    })
    • 异步加载组件

    一个推荐的做法是将异步组件和 webpack 的 code-splitting 功能一起配合使用,参考使用了 vuex 插件的 路由加载 About 的方式 这段特殊注释不是多余的 : /* webpackChunkName: "about" */

      {
        path: '/about',
        name: 'About',
        // route level code-splitting
        // this generates a separate chunk (about.[hash].js) for this route
        // which is lazy-loaded when the route is visited.
        component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
      }
    • 异步加载时处理加载状态

    这里的异步组件工厂函数也可以返回一个如下格式的对象:

    const AsyncComponent = () => ({
      // 需要加载的组件 (应该是一个 `Promise` 对象)
      component: import('./MyComponent.vue'),
      // 异步组件加载时使用的组件
      loading: LoadingComponent,
      // 加载失败时使用的组件
      error: ErrorComponent,
      // 展示加载时组件的延时时间。默认值是 200 (毫秒)
      delay: 200,
      // 如果提供了超时时间且组件加载也超时了,
      // 则使用加载失败时使用的组件。默认值是:`Infinity`
      timeout: 3000
    })

    day12

    2020.08.18

    • 访问根实例

    子组件可以通过$root 属性访问根实例

    // 获取根组件的数据
    this.$root.foo
    
    // 写入根组件的数据
    this.$root.foo = 2
    
    // 访问根组件的计算属性
    this.$root.bar
    
    // 调用根组件的方法
    this.$root.baz()

    在绝大多数情况下,推荐使用 Vuex 来管理应用的状态。

    day13

    2020.08.20

    • 访问父级组件实例

    一个google地图的例子

    • 访问子组件实例或子元素

    如果需要在javascript直接访问子组件时,可以在使用子组件时加入 ref 属性,如:

    <base-input ref="usernameInput"></base-input>

    可以使用 this.$refs.usernameInput 来访问这个 <base-input> 实例

    • 依赖注入

    在父级元素中提供 provide

    provide: function () {
      return {
        getMap: this.getMap
      }
    }

    在子元素实例使用 inject 接收指定的我们想要添加在这个实例上的 property:

    inject: ['getMap']

    依赖注入的google map实例

    依赖注入所提供的 property 是非响应式的,你想要共享的这个 property 是你的应用特有的,而不是通用化的,或者如果你想在祖先组件中更新所提供的数据,那么这意味着你可能需要换用一个像 Vuex 这样真正的状态管理方案了。

    • 程序化的事件侦听器 (@todo)
    • 通过 $on(eventName, eventHandler) 侦听一个事件
    • 通过 $once(eventName, eventHandler) 一次性侦听一个事件
    • 通过 $off(eventName, eventHandler) 停止侦听一个事件

    日期选择器实例

    • 递归组件

    组件是可以在它们自己的模板中调用自身的。不过它们只能通过 name 选项来做这件事:

    name: 'stack-overflow',
    template: '<div><stack-overflow></stack-overflow></div>'

    类似上述的组件将会导致“max stack size exceeded”错误,所以请确保递归调用是条件性的 (例如使用一个最终会得到 false 的 v-if)。

    • 组件之间的循环引用

    我们先把两个组件称为 A 和 B。模块系统发现它需要 A,但是首先 A 依赖 B,但是 B 又依赖 A,但是 A 又依赖 B,如此往复。这变成了一个循环,不知道如何不经过其中一个组件而完全解析出另一个组件。为了解决这个问题,我们需要给模块系统一个点,在那里“A 反正是需要 B 的,但是我们不需要先解析 B。”

    <tree-folder> 组件设为了那个点。我们知道那个产生悖论的子组件是 <tree-folder-contents> 组件,所以我们会等到生命周期钩子 beforeCreate 时去注册它:

    beforeCreate: function () {
      this.$options.components.TreeFolderContents = require('./tree-folder-contents.vue').default
    }

    或者 webpack 异步 import

    components: {
      TreeFolderContents: () => import('./tree-folder-contents.vue')
    }
    • 内联模板

    inline-template 属性,内联模板需要定义在 Vue 所属的 DOM 元素内。

    <my-component inline-template>
      <div>
        <p>These are compiled as the component's own template.</p>
        <p>Not parent's transclusion content.</p>
      </div>
    </my-component>
    • X-Template

    x-template 需要定义在 Vue 所属的 DOM 元素外。

    <script type="text/x-template" id="hello-world-template">
      <p>Hello hello hello</p>
    </script>
    
    Vue.component('hello-world', {
      template: '#hello-world-template'
    })
    
    • 通过 v-once 创建低开销的静态组件

    有的时候你可能有一个组件,这个组件包含了大量静态内容。在这种情况下,可以在根元素上添加 v-once attribute 以确保这些内容只计算一次然后缓存起来

    Vue.component('terms-of-service', {
      template: `
        <div v-once>
          <h1>Terms of Service</h1>
          ... a lot of static content ...
        </div>
      `
    })

    过渡 & 动画(@todo)

    Vue 在插入、更新或者移除 DOM 时,提供多种不同方式的应用过渡效果。

    • 在 CSS 过渡和动画中自动应用 class
    • 可以配合使用第三方 CSS 动画库,如 Animate.css
    • 在过渡钩子函数中使用 JavaScript 直接操作 DOM
    • 可以配合使用第三方 JavaScript 动画库,如 Velocity.js

    vue router

    官方文档

    免费课程

    day15

    2020.08.25

    一个 materialize UI类库

    Firebase

    当前建立的firebase项目为 udemy-ninja-smoothies

    firebase api信息

     // Your web app's Firebase configuration
      var firebaseConfig = {
        apiKey: "AIzaSyAY6uN7BCWS4licC7Yeyn_i9qE6Ceji-rs",
        authDomain: "udemy-ninja-smoothies-fab0d.firebaseapp.com",
        databaseURL: "https://udemy-ninja-smoothies-fab0d.firebaseio.com",
        projectId: "udemy-ninja-smoothies-fab0d",
        storageBucket: "udemy-ninja-smoothies-fab0d.appspot.com",
        messagingSenderId: "968931780652",
        appId: "1:968931780652:web:6678a7f3690b7d6330c989",
        measurementId: "G-K0S8B25CWF"
      };
      // Initialize Firebase
      firebase.initializeApp(firebaseConfig);
      firebase.analytics();

    vue 整合firebase /firestore

    day16

    2020.08.27

    使用预处理器

    部署到firebase

    • 安装 Firebase CLI
    npm install -g firebase-tools
    • 初始化您的项目

    请打开终端窗口,转到 Web 应用的根目录,或为 Web 应用创建根目录

    登录 Google

    firebase login

    启动项目 从该应用的根目录中运行此命令:

    firebase init
    • npm run build

    • 部署到 Firebase 托管

    firebase deploy

    Project Console: https://console.firebase.google.com/project/udemy-ninja-smoothies-fab0d/overview

    Hosting URL: https://udemy-ninja-smoothies-fab0d.web.app

    day17

    2020.08.29-2020.08.30

    Firebase两种类型数据库比较

    js时间日期处理库

    vue-chat-scroll插件

    新内容添加时自动滚动到元素最底端,如聊天记录,用法

    import Vue from 'vue'
     
    import VueChatScroll from 'vue-chat-scroll'
    Vue.use(VueChatScroll)

    day18

    2020.08.31

    Firebase控制台

    google apis console(包括google map)

    创建 google map API密钥

    • 打开google apis console,导航处选择对应的项目。
    • 点击 ENABLE APIS AND SERVICES按钮,搜索或点击 Maps JavaScript API的方块,在出现的按钮点击启用
    • 启用后会跳转到报表页,这时点击页眉的抽屉导航,在菜单中 选择API与服务 > 凭据 ,在出现的右上方标签位置点 +创建凭据 ,选择API密钥

    弹出图层:

    在您的应用中使用此密钥的方法是 key=API_KEY 参数传递此密钥
    
    AIzaSyBSaj2YcxYDzAnGV_OomO5CCMkj9-HRC1k
    您的 API 密钥

    引入:

    <script defer
      src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap">
    </script>

    相关用法和文档 https://cloud.google.com/maps-platform

    粘贴上传文件

    原理及简单示例

    应用在vue,请忽略作者的中式英语

    text-field-edit

    • it doesn't break the undo history (in supported browsers)
    • it fires an input event (with event.inputType === 'insertText')
    • it's the most efficient way of adding/replacing selected text in a field
    • it's cross-browser (modern browsers)

    fineuploader

    很遗憾,作者不再维护了。

    uppy文件上传

    可替代 fineuploader

JavaScript
1
https://gitee.com/falcon/vue-firebase-study.git
git@gitee.com:falcon/vue-firebase-study.git
falcon
vue-firebase-study
vue-firebase-study
master

搜索帮助