lt;!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>vue組件的模板分離寫法</title>
<style type="text/css">
.hezi{
width: 300px;
height: 250px;
border: #000000 solid 1px;
}
</style>
</head>
<body>
<div id="app">
<cpn></cpn>
</div>
<script src="../js/vue.js"></script>
<!--1.script標簽, 注意:類型必須是text/x-template-->
<!-- <script type="text/x-template" id="app-hezi">
<div class="hezi">
<h1>我是h1標題</h1>
<p>我是p標簽</p>
</div>
</script> -->
<!--2.template標簽-->
<template id="app-hezi">
<div class="hezi">
<h1>我是h1標題</h1>
<p>我是p標簽</p>
</div>
</template>
<script type="text/javascript">
Vue.component('cpn',{
template: '#app-hezi'
})
const app=new Vue({
el: '#app',
data:{
}
})
</script>
</body>
</html>
、明確前后端分離和前后端不分離的概念:
我的理解:前后端不分離的概念是后端要控制前端的數據顯示和模板渲染(django),它有一個缺點就是可復用性不強,也就是它的后端程序只適用于一種前端類型,比如返回的是網頁模板,則它只能用于網頁端,移動端要用只能重新渲染一個移動端的模板。
而前后端分離則解決了這一問題,它的可復用性極強,一個后端可對接多個類型的前端,因為它不使用模板,而是通過向前端傳遞json數據的方式,將頁面渲染和顯示數據交給前端去做。這樣寫出來的后端可以適用于任何類型的前端。
二、項目的數據庫設計:
三、模型類設計
class BaseModel(object):
"""模型基類,為每個模型補充創建時間與更新時間"""
create_time=db.Column(db.DateTime, default=datetime.now) # 記錄的創建時間
update_time=db.Column(db.DateTime, default=datetime.now, onupdate=datetime.now) # 記錄的更新時間
class User(BaseModel, db.Model):
"""用戶"""
__tablename__= "ih_user_profile"
id=db.Column(db.Integer, primary_key=True) # 用戶編號
name=db.Column(db.String(32), unique=True, nullable=False) # 用戶暱稱
password_hash=db.Column(db.String(128), nullable=False) # 加密的密碼
mobile=db.Column(db.String(11), unique=True, nullable=False) # 手機號
real_name=db.Column(db.String(32)) # 真實姓名
id_card=db.Column(db.String(20)) # 身份證號
avatar_url=db.Column(db.String(128)) # 用戶頭像路徑
houses=db.relationship("House", backref="user") # 用戶發布的房屋
orders=db.relationship("Order", backref="user") # 用戶下的訂單
class Area(BaseModel, db.Model):
"""城區"""
__tablename__= "ih_area_info"
id=db.Column(db.Integer, primary_key=True) # 區域編號
name=db.Column(db.String(32), nullable=False) # 區域名字
houses=db.relationship("House", backref="area") # 區域的房屋
# 房屋設施表,建立房屋與設施的多對多關系
house_facility=db.Table(
"ih_house_facility",
db.Column("house_id", db.Integer, db.ForeignKey("ih_house_info.id"), primary_key=True), # 房屋編號
db.Column("facility_id", db.Integer, db.ForeignKey("ih_facility_info.id"), primary_key=True) # 設施編號
)
class House(BaseModel, db.Model):
"""房屋信息"""
__tablename__= "ih_house_info"
id=db.Column(db.Integer, primary_key=True) # 房屋編號
user_id=db.Column(db.Integer, db.ForeignKey("ih_user_profile.id"), nullable=False) # 房屋主人的用戶編號
area_id=db.Column(db.Integer, db.ForeignKey("ih_area_info.id"), nullable=False) # 歸屬地的區域編號
title=db.Column(db.String(64), nullable=False) # 標題
price=db.Column(db.Integer, default=0) # 單價,單位:分
address=db.Column(db.String(512), default="") # 地址
room_count=db.Column(db.Integer, default=1) # 房間數目
acreage=db.Column(db.Integer, default=0) # 房屋面積
unit=db.Column(db.String(32), default="") # 房屋單元, 如幾室幾廳
capacity=db.Column(db.Integer, default=1) # 房屋容納的人數
beds=db.Column(db.String(64), default="") # 房屋床鋪的配置
deposit=db.Column(db.Integer, default=0) # 房屋押金
min_days=db.Column(db.Integer, default=1) # 最少入住天數
max_days=db.Column(db.Integer, default=0) # 最多入住天數,0表示不限制
order_count=db.Column(db.Integer, default=0) # 預訂完成的該房屋的訂單數
index_image_url=db.Column(db.String(256), default="") # 房屋主圖片的路徑
facilities=db.relationship("Facility", secondary=house_facility) # 房屋的設施
images=db.relationship("HouseImage") # 房屋的圖片
orders=db.relationship("Order", backref="house") # 房屋的訂單
class Facility(BaseModel, db.Model):
"""設施信息"""
__tablename__= "ih_facility_info"
id=db.Column(db.Integer, primary_key=True) # 設施編號
name=db.Column(db.String(32), nullable=False) # 設施名字
class HouseImage(BaseModel, db.Model):
"""房屋圖片"""
__tablename__= "ih_house_image"
id=db.Column(db.Integer, primary_key=True)
house_id=db.Column(db.Integer, db.ForeignKey("ih_house_info.id"), nullable=False) # 房屋編號
url=db.Column(db.String(256), nullable=False) # 圖片的路徑
class Order(BaseModel, db.Model):
"""訂單"""
__tablename__= "ih_order_info"
id=db.Column(db.Integer, primary_key=True) # 訂單編號
user_id=db.Column(db.Integer, db.ForeignKey("ih_user_profile.id"), nullable=False) # 下訂單的用戶編號
house_id=db.Column(db.Integer, db.ForeignKey("ih_house_info.id"), nullable=False) # 預訂的房間編號
begin_date=db.Column(db.DateTime, nullable=False) # 預訂的起始時間
end_date=db.Column(db.DateTime, nullable=False) # 預訂的結束時間
days=db.Column(db.Integer, nullable=False) # 預訂的總天數
house_price=db.Column(db.Integer, nullable=False) # 房屋的單價
amount=db.Column(db.Integer, nullable=False) # 訂單的總金額
status=db.Column( # 訂單的狀態
db.Enum(
"WAIT_ACCEPT", # 待接單,
"WAIT_PAYMENT", # 待支付
"PAID", # 已支付
"WAIT_COMMENT", # 待評價
"COMPLETE", # 已完成
"CANCELED", # 已取消
"REJECTED" # 已拒單
),
default="WAIT_ACCEPT", index=True)
comment=db.Column(db.Text) # 訂單的評論信息或者拒單原因
四、數據庫遷移
python manage.py db init
python manage.py db migrate -m 'init tables'
五、項目架構
5.1項目的整體目錄如下圖所示:
5.2 ihome的目錄結構:
六、項目整體架構配置:
6.1主目錄下config.py文件主要是配置數據庫和redis緩存
6.2 ihome目錄下的__init__.py文件主要是創建app對象:
6.3主目錄下的manage.py用來運行項目代碼:
6.4 ihome目錄下的web_html.py文件用來配置靜態文件的藍圖
6.5在ihome/utils/commons.py文件中定義正則轉換器:
現在我們來看看為什么在Vue中推薦注冊組件是使用駝峰寫法, 在了解這個之前,詳細大家應該都能明白為什么在Vue中, 局部組件的使用頻率高于全局組件.
推薦使用駝峰寫法也是和局部組件有關系
我們先看一個示例
<div id="app">
<!-- 3. 在注冊了局部組件的實例中使用局部組件 -->
<my-component></my-component>
</div>
<script>
// 1. 創建局部組件的選項對象
let MyComponent={
template: `
<div>
<h2>局部組件</h2>
</div>
`,
}
const vm=new Vue({
el:"#app",
// 2. 將選項對象注冊為局部組件
components: {
"my-component": MyComponent
}
})
</script>
通過前面的學習,這個例子應該已經熟悉了,
示例中,不使用駝峰命名組件,依然可以正常運行,那么為什么組件名還要推薦使用駝峰命名
那先看下面幾點:
好此時大家想一想,如果組件名和選項對象的變量名一樣會怎么樣
是不是就會變成如下的寫法
const vm=new Vue({
el:"#app",
components: {
MyComponent: MyComponent
}
})
在思考一下,我們之前在學習ES6的時候講過在定義對象的是有一種簡便寫法. 當屬性跟值長得一樣時,就可以簡寫
因此這里我們就可以簡寫為
const vm=new Vue({
el:"#app",
components: {
MyComponent
}
})
所以,為什么推薦使用駝峰寫法,這里就應該可以看出端倪了, 如果我們定義組件的組件名使用駝峰寫法,也就是和需要被注冊為組件的選項對象一致是,我們注冊組件將變得簡單
如果此時需要注冊n個組件,就可以如下寫法
const vm=new Vue({
el:"#app",
components: {
one,two,three,four.....
}
})
是不是感覺很優雅,
總結:
盡管語法糖簡化了組件注冊,但在template選項中拼接HTML元素比較麻煩,這也導致了HTML和JavaScript的高耦合性。
Vue.js提供了兩種方式將定義在JavaScript中的HTML模板分離出來。
在使用script標簽將template模板分離出來時,要注意script標簽的type類型選擇,
<div id="app">
<!-- 3. 使用組件 -->
<my-component></my-component>
</div>
<!-- 組件模板 -->
<!-- 注意: 如果不添加type屬性,可能會顯示效果,但是會報錯, -->
<script id="myComponent" type="text/x-template">
<div>
<h2>我想被創建為局部組件</h2>
</div>
</script>
<script>
// 1. 創建組件選項對象
let MyComponent={
// 此時的模板template的值就是一個選擇器
template: "#myComponent",
}
const vm=new Vue({
el:"#app",
// 2. 注冊組件
components: {
"my-component": MyComponent
}
})
</script>
template選項現在不再是HTML元素,而是一個id,Vue.js根據這個id查找對應的元素,然后將這個元素內的HTML作為模板進行編譯。
注意:
使用<script> 標簽時,type指定為text/x-template,意在告訴瀏覽器這不是一段js腳本,瀏覽器在解析HTML文檔時會忽略<script>標簽內定義的內容。
如果使用<template>標簽,則不需要指定type屬性。
<div id="app">
<!-- 3. 使用組件 -->
<my-component></my-component>
</div>
<!-- 組件模板 -->
<!-- template標簽不需要指定type,標簽的本意就是告訴瀏覽器這是模板 -->
<template id="myComponent">
<div>
<h2>我想被創建為局部組件</h2>
</div>
</template>
<script>
// 1. 創建組件選項對象
let MyComponent={
// 此時的模板template的值就是一個選擇器
template: "#myComponent",
}
const vm=new Vue({
el:"#app",
// 2. 注冊組件
components: {
"my-component": MyComponent
}
})
</script>
在理解了組件的創建和注冊過程后,我建議使用<script>或<template>標簽來定義組件的HTML模板。
這使得HTML代碼和JavaScript代碼是分離的,便于閱讀和維護。
另外,在Vue.js中,可創建.vue后綴的文件,.vue文件就是一個組件,成為單文件組件,這個內容我會在后面的文章介紹。
組件中的選項基本與實例選項對象一致, 但是有兩個選項是特例,分別為el 和 data 屬性
這個說的特例是指組件的選項對象和實例選項對象使用的不同
el屬性的作用我們都了解了, 就是在實例中使用,決定Vue需要接管的DOM元素. 組件是在實例中使用,所以不需要el屬性,
如果一個選項對象被注冊為組件,添加el屬性就會造成報錯,
// 1. 創建局部組件的選項對象
let MyComponent={
el:"",
template: "#myComponent",
}
const vm=new Vue({
el:"#app",
// 2. 將選項對象注冊為局部組件
components: {
"my-component": MyComponent
}
})
// 會報錯, 告訴你el屬性只能在實例中使用
可以通過報錯信息了解到, el選項只能使用在new創建的vue實例上
組件中的data選項必須是一個函數,返回一個數據對象.
為什么需要是一個函數,而不可以像Vue實例的選項對象一樣是一個對象呢
不能使用對象的原因:
這樣就會出現問題,看代碼:
示例代碼如下:
<div id="app">
<!-- 3. 使用組件 -->
<my-component></my-component>
<my-component></my-component>
<my-component></my-component>
</div>
<template id="myComponent">
<div>
<h2>組件{{num}}</h2>
<button @click="handleClick">點擊+1</button>
</div>
</template>
<script>
// 組件共享數據
let data={
num : 10
}
// 1. 選項對象
let MyComponent={
template: "#myComponent",
data: function(){
return data
},
methods: {
handleClick(){
this.num++
}
}
}
const vm=new Vue({
el:"#app",
// 2. 注冊組件
components: {
"my-component": MyComponent
}
})
</script>
示例結果:
實例說明:
通過案例我們就會發現如果所有的組件都共享數據,當有一個組件中的數據發生了變化,所有的組件顯示的數據都會發生變化, 這不是我們想要的,
所以組件的data數據屬性才會需要函數,每次初始化化的時候都會執行函數,將返回的結果作為組件的數據,
這樣每次執行函數都會給每個組件創建一個獨立的數據
<div id="app">
<!-- 3. 使用組件 -->
<my-component></my-component>
<my-component></my-component>
<my-component></my-component>
</div>
<template id="myComponent">
<div>
<h2>組件{{num}}</h2>
<button @click="handleClick">點擊+1</button>
</div>
</template>
<script>
// 1. 選項對象
let MyComponent={
template: "#myComponent",
data: function(){
// 每次函數執行都會返回新的數據,非共享數據
return {
num : 10
}
},
methods: {
handleClick(){
this.num++
}
}
}
const vm=new Vue({
el:"#app",
// 2. 注冊組件
components: {
"my-component": MyComponent
}
})
</script>
顯示結果:
通過示例就會發現, 當一個組件數據發生改變的時候, 其他組件的數據不會變化,因為每個組件都有自己獨立的數據
當注冊組件 (或者 prop) 時,可以使用 kebab-case (短橫線分隔命名)、camelCase (駝峰式命名) 或 PascalCase (單詞首字母大寫命名)。
// 在組件定義中
components: {
// 使用 kebab-case 注冊
'kebab-cased-component': { /* ... */ },
// 使用 camelCase 注冊 俗稱小駝峰
'camelCasedComponent': { /* ... */ },
// 使用 PascalCase 注冊 俗稱大駝峰
'PascalCasedComponent': { /* ... */ }
}
在 HTML 模板中,請使用 kebab-case:
<!-- 在 HTML 模板中始終使用 kebab-case -->
<kebab-cased-component></kebab-cased-component>
<camel-cased-component></camel-cased-component>
<pascal-cased-component></pascal-cased-component>
這個問題已經在前面認真探討過了,這里不再詳細闡述
通過上面上的例子我們已經了解了組件的使用,就是把組件名當做自定義標簽使用,但是這種使用方法有的時候也會出現問題,
通過下面的實例了解組件標簽解析是發生的問題.
例如:實例代碼如下
<div id="app">
<!-- 3. 使用組件 -->
<table>
<tbody>
<row></row>
<row></row>
<row></row>
</tbody>
</table>
</div>
<!-- 組件模板 -->
<template id="myComponent">
<tr>
<td>內容</td>
<td>123</td>
</tr>
</template>
<script>
// 1. 組件選項對象
let MyComponent={
template: "#myComponent",
}
// 2. 注冊組件
const vm=new Vue({
el:"#app",
components: {
"row": MyComponent
}
})
</script>
顯示結果:
實例中的寫法,在查看代碼結構時,發現子組件的tr標簽并不在tbody里,
原因在與瀏覽器規范中tbody標簽里面必須放tr標簽,但是我們放的是row自定義標簽,所以在解析的時候就會出問題
諸如此類的還有ul,ol標簽里只能放li標簽, select標簽中只能放option,這些都是需要注意的事項
那么我們怎么解決這類問題呢?
vue允許我們使用is屬性來使用組件, is屬性的值是組件名
所以可以采用is屬性來制定組件
示例代碼如下:
<div id="app">
<!-- 3. 使用組件 -->
<table>
<tbody>
<tr is="row"></tr>
<tr is="row"/>
<tr is="row"/>
</tbody>
</table>
</div>
顯示結果:
此時我們就會發現不僅結果沒問題, 編譯后標簽的嵌套也沒有什么問題,
因為我們是按照標準在tbody標簽中使用的是tr標簽,只不過通過is屬性將tr標簽替換為了組件row的模板標簽.
此時tr標簽中沒有嵌套內容,所有使用單標簽,雙標簽都可以
*請認真填寫需求信息,我們會在24小時內與您取得聯系。